Tomcat中的Connector和Container

Tomcat中的一些关于Connector和Container的小知识。 
其实在这两个组件都是我们所熟悉的组件,在一个Tomcat中分布有多个Connector和一个Container,至于多个Connector的话,其实很容易理解,比如我们需要监听STARTUP和SHUTDOWN命令,那么我们就开一开多个连接,分别监听不同的端口号了,当然不同的协议也可以开多个连接的,例如我们可以看一下Tomcat中的server.xml的配置:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
1
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
1
2
3
这里的两个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);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Host,Context的调用下层容器的方法与本方法大概一致,所以通过这种方法就可以将对象一层一层的传递下去,并且最后由Servlet进行处理。 
好了,今天就先分享这些,谢谢大家,如有错误或者不当之处,请多多指教。
————————————————
版权声明:本文为CSDN博主「De-Bug」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34985719/article/details/78386183

发布了28 篇原创文章 · 获赞 16 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/sunboylife/article/details/103729126