Tomcat中的Connector和Container

来源:互联网 发布:网络作家收入100排行榜 编辑:程序博客网 时间:2024/04/28 03:22

大家好,由于楼主前些天身体不太舒服所以就一直没有更新博客,后来身体恢复后一直沉迷吃鸡,不能自拔,所以断更很长时间。本来有一篇博客已经写好主要是写JAVA中Servlet的继承结构,但是后来草稿不知怎么的没了,又找不回当时的思路来写,所以这一篇重新开题,和大家一起分享Tomcat中的一些关于Connector和Container的小知识。
其实在这两个组件都是我们所熟悉的组件,在一个Tomcat中分布有多个Connector和一个Container,至于多个Connector的话,其实很容易理解,比如我们需要监听STARTUP和SHUTDOWN命令,那么我们就开一开多个连接,分别监听不同的端口号了,当然不同的协议也可以开多个连接的,例如我们可以看一下Tomcat中的server.xml的配置:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"               clientAuth="false" sslProtocol="TLS" />

这里的两个Connector分别配置监听了Http协议和AJP协议,其实实际上,这两个代码片在xml文件中是被注释起来的。
解释完Connector为什么会有多个以后,我们来看一下Connector的结构:
这里写图片描述
首先,Connector中内聚了一个ProtociolHandler,Connector的主要功能基本都是依靠ProtocolHandler来处理,该类的创建以及初始化是在Connector的启动过程中完成的,具体内容参见《看透SpringMVC》一书。在ProtooclHandler中,主要有三个组件,EndPoint,Processor以及Adapter。
EndPointer主要任务是完成对普通Socket的接收,并做部分处理后将处理的Socket传给Processor,而Processor主要任务是完成对Socket的转换,主要时报Socket转换成Request,然后封装好了的Request将会传给Adapter,Adapter将会将请求路由给Container,Container中的处理流程我们下面会讲到。
从上面的描述中我们可以判断,EndPoint主要实现了HTTP协议,而负责封装Socket的Processor则主要实现了TCP/IP协议。那么EndPointer中的二级组件的任务是什么呢?其实这三个组件中,Acceptor以及AsyncTimeout是两个内部类,但是Handler是一个接口,三个组件都需要子类去具体实现,Acceptor的主要作用是为了监听请求,而Handler是为了处理接受到的Socket并在内部调用了Processor进行处理。而AsyncTimeout则与我们常用的超时处理有关,我们知道,在我们使用网络请求中,通常会设置超时时间,包括读取超时以及连接超时,那么这些设置便是由这个组件进行监听的。
那么当Container接收到Connector发送的Request之后会怎么处理呢?这里涉及到一个设计模式,叫做责任链模式。
首先,我们看一下Container的组成结构:
这里写图片描述
可能图片表述不是很清楚,我来解释一下,在一个Container中会存在一个Engine,有且只有一个,Engine下会有多个Host,表示站点或者是虚拟主机,然后一个Host下会有多个Context,表示多个应用,然后一个Context下会有多个Wrapper,表示多个servlet。那么他们的继承关系是怎么样的呢:
这里写图片描述
博主能力有限,这个不标准的类图大家就先凑活着看一下:
首先Lifecycle是一个接口,默认实现为LifecycleBase,这个接口的主要作用是实现了生命周期管理,也就是说所有实现生命周期的组件都统一实现了该接口,以实现其生命周期中的过程。图中Container接口实现了Lifecycle接口,也就是所Container具有生命周期,之后Container接口有一个默认实现,就是ContainerBase,有四个子接口分别是前面我们说过的Context,Engine,Wrapper和Host,然后对应的默认实现分别是StandardXXX,其具体的生命周期过程我们在这里不做详细的解释,下面我们说一下前面提到的责任链模式:
这里写图片描述
通过图片我们可以看出当一个请求发送到Container中时,首选先回经过Engine的管道,然后被管道中的各个处理者拦截,拦截之后被处理并交由下一个处理者,这一点和传统的责任链模式没有区别,但是我们返现在管道的最后会有一个StardandXXXValve,这个是最后的BaseValve,是一个管道中,必须存在的处理者,前面的处理者在代码中是一个链表存储,头节点被first属性引用,但是BaseValve由basic属性引用,BaseVavle的主要作用就是将处理对象交由下一层的管道继续处理。以Engine的代码为例:

public final invoke(Request request, Reponse reponse){        //host已经提前存储在了request中        Host host = request.getHost();        if (host == null) {            .......            //host为空的处理逻辑        }        if(request.isAsyncSupported()){            request.setAsyncSupported(host.getPipeline().isAsyncSupported());        }        host.getPipeline().getFirst().invoke(request,reponse);    }

Host,Context的调用下层容器的方法与本方法大概一致,所以通过这种方法就可以将对象一层一层的传递下去,并且最后由Servlet进行处理。
好了,今天就先分享这些,谢谢大家,如有错误或者不当之处,请多多指教。