关于tomcat服务器的分析(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pickers/article/details/79340846
前言:这次主要对我之前了解到的tomcat原理进行总结分享,知识基本来自于公众号:架构师的小秘密。因为我本身并没有从源码级别阅读过这整个过程,所以这边大概提供了下思路,具体还得读源码。

首先可以根据一张图片大致了解下:
tomcat最顶层就是server服务器,他只有一个,然而这下面有很多service来提供不同的服务,每个service又由connector和container组成,这两个才是整个tomcat的根基所在。
1、Connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转化; 
2、Container用于封装和管理Servlet,以及具体处理Request请求;
其中一个service可以有多个connector,但只能有有个container。因为一个服务器可以支持不同协议的连接,比如http和https,亦可支持不同端口。
其中整个服务器控制流程是service控制connector和container,而service是依赖于server环境生存的,所以整个生命周期由server控制。这样的话关于之前做微信的时候遇到的端口号占用,修改的时候就是修改这个server的相关配置,其中具体的配置文件server.xml可以在tomcat的解压目录下的conf目录下的server.xml配置(服务器基本就是下载个压缩包,然后解压后配置下jdk环境,配置下相关环境变量,如有需要修改下端口号,之后点击启动文件即可启动),具体server.xml文件如下所示,默认监听端口是8080.
比如上图所示的8005端口对应的server标签直接就是关闭tomcat的端口。。。从上图可以很清楚的看到server和service与connector对应的关系,其中engine和host其实都是container的子部分,后面会介绍到的。
看到这里,大概总结下具体框架,其实tomcat只有一个server,相当于一个大的容器,里面可以存在很多service,而service具体是由connector和container来相关内容的操作的。整个过程中server的权利最大,直接控制整个tomcat,而其中的service是对外提供服务的,connector用于接收请求并且将请求封装成request和response做具体处理,container用于封装和管理servlet,以及具体处理request请求。(如果没做过java服务器开发的话,对这些术语会比较模糊,其实对于服务器端的开发人员来说,基本都是在做container层的开发,直接通过api来进行相关开发,一般的话servlet是对外的接口,正常的话会先提供一个jsp页面给用户,用户进行相关操作来访问你的servlet页面,servlet相当于后台处理,我记得之前的话好像里面有了一个doGet和doPost的方法,其实两个基本都调用doGet,然后可以获取到相关信息,其中可以自己搞一个类(相当于c语言的结构体)把这个东西存储起来,其实就是个bean,之后控制下一步怎么弄,是继续访问还是说返回给用户提示信息,这些都有相关api可提供操作,这里面如果复杂点涉及到一些框架,spring,springboots等等,这还涉及到数据库的访问优化,一般数据库有用mysql或者orcle,操作框架一般使用himbernat,基本就是导入jar包,配置相关配置,还有难点的就是一些入口的访问,比如以下浏览量太多,服务器会不会挂掉等等,这些可以用cdn啊等等,更有甚者可以不同的资源访问不同的服务器,相当于分流了,,,扯多了,这些只是基本,还是有很多可以深挖的知识点的)。
ok,接下来就详细的说下container层和connector层具体是怎么提供服务的。
其实说一个请求被发送到tomcat之后,首先经过service然后会交给我们的connector,connector用于接收请求并将接收到的请求封装为request和response,封装完了之后交给container进行具体处理,container处理完请求之后再返回给connector,最后再由connector经过socket将处理的结果返回给客户端,这样基本就处理完了整个请求。其中connector最底层使用的是socket来进行连接的,request和response是按照HTTP协议来进行封装的,所以connector需要同时实现TCP/IP协议和HTTP协议。tomcat既然处理请求,那么肯定需要先接受到这个请求,接受请求我们首先看一下connector。
首先,先看几个问题。connector是怎么接受请求的?如何将请求封装成request和response的?封装完之后的request和response如何交给container进行处理的?container处理完之后如何交给connector并返回给客户端的?
connect结构图如下:
Connector就是使用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型,比如:Http11Protocol使用的是普通Socket来连接的,Http11NioProtocol使用的是NioSocket来连接的。
其中ProtocolHandler由包含了三个部件:Endpoint、Processor、Adapter。
(1)Endpoint用来处理底层Socket的网络连接,Processor用于将Endpoint接收到的Socket封装成Request,Adapter用于将Request交给Container进行具体的处理。
(2)Endpoint由于是处理底层的Socket网络连接,因此Endpoint是用来实现TCP/IP协议的,而Processor用来实现HTTP协议的,Adapter将请求适配到Servlet容器进行具体的处理。
(3)Endpoint的抽象实现AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口。Acceptor用于监听请求,AsyncTimeout用于检查异步Request的超时,Handler用于处理接收到的Socket,在内部调用Processor进行处理。
关于最后一个问题,我们需要分析下container的实现结构。
container是用于封装和管理servlet,以及具体处理request请求,在connector内部包含了4个子容器,如下图:
(1)Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine; 
(2)Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点; 
(3)Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件; 
(4)Wrapper:每一Wrapper封装着一个Servlet;
可以先看下tomcat服务器解压缩后的目录:
基本上我们写的服务器的demo都放在webapps下面,比如一般所说的打war包,其实这个就方便交付和部署,比如说我在本地上开发了一个服务器项目,然后本地测试ok,那么就需要上传到服务器,这个过程其实是有坑的,一般的话就是在本地eclipse上面直接打war包,之后将war包直接丢到服务器的webapps下面,重启下服务器会自动部署。说实话之前有个同事问我那个服务器端启动报错的事情,我特么到现在也没有搞清楚,想再分析下,找不到之前的报错log了,尴尬。
其中比如说我开发了下一个服务端程序名叫demo,那么直接将demo拷贝到webapps目录下,然后输入http://localhost:8080/demo 即可进行访问。
关于container是如何处理请求并且将结果返回connector的,这个我不是很理解,因为基本没用过,直接将原作者的说法抄下,如下所示:

Container处理请求是使用Pipeline-Value管道来处理的!
Pipeline-Value是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将处理后的请求返回,再让下一个处理着继续处理。
(1)每个Pipeline都有特定的Value,而且是在管道的最后一个执行,这个Value叫做BaseValue,BaseValue是不可删除的;
(2)在上层容器的管道的BaseValue中会调用下层容器的管道。
我们知道Container包含四个子容器,而这四个子容器对应的BaseValue分别在:StandardEngineValue、StandardHostValue、StandardContextValue、StandardWrapperValue。
具体流程如下:
(1)container在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline(Engine的管道);
(2)在Engine的管道中依次会执行EngineValue1、EngineValue2等等,最后会执行StandardEngineValue,在StandardEngineValue中会调用Host管道,然后再依次执行Host的HostValue1、HostValue2等,最后在执行StandardHostValue,然后再依次调用Context的管道和Wrapper的管道,最后执行到StandardWrapperValue。
(3)当执行到StandardWrapperValue的时候,会在StandardWrapperValue中创建FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着我们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用所有的Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理!(这个科普下,其中服务器有个过滤器的功能,设置的就是filter)
(4)当所有的Pipeline-Value都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端。


ok,到这里基本上整个tomcat大致的解析和处理架构就是这样,其实这个只是简单地科普,不涉及算法,不涉及其他高深的东西,有人说为什么要了解这些,emmm,怎么说呢,也不是因为兴趣,就是总得多了解点,总是用这些,不了解下感觉比较慌,毕竟咱是要做个博学的人~~~总不能总是被人鄙视成小白吧。
接下来有时间会刷下leetcode的题目,是时候提升波智商了~~~

猜你喜欢

转载自blog.csdn.net/pickers/article/details/79340846