宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取

  在Tomcat中,连接器的名字是Coyote,是Tomcat服务器提供的外部访问的接口。外部即客户端通过Coyote即连接器与服务器建立连接、发送请求和接受响应。

  连接器对 Servlet 容器屏蔽了协议及 I/O 模型等的区别,无论是 HTTP 还是 AJP,在容器中获取到的都是一个标准的 ServletRequest 对象。连接器封装了底层的网络通信信息,包含Socket请求及响应处理,为容器(Catalinna)提供了统一的接口,容器从连接器拿到的是连接器封装后的请求对象ServletRequest,使容器与具体的请求协议以及I/O操作方式完全解耦.容器处理完请求后,容器通过连接器提供的Response对象将结果下入输出流中。

  连接器Coyote作为独立的模块,负责的是具体协议的解析和I/O的相关操作。与Servlet规范实现没有直接关系。

                                                                                      Tomcat的连接器-Coyote-编程部落

 连接器的核心组件

  在探索连接器组件前先总结一下连接器的功能主要:

                                                            Tomcat的连接器-Coyote-编程部落

  可以看出连接器需要完成的三个高内聚功能是网络通信,应用层协议解析,Tomcat Request/Response 与 ServletRequest/ServletResponse 的转化。而Tomcat的设计者通过Endpoint、Processor 和 Adapter这三个组件来实现这三个功能的, 其中 Endpoint 和 Processor 放在一起抽象成了 ProtocolHandler 组件,它们的关系如下图所示

                                                                   Tomcat的连接器-Coyote-编程部落

  Endpoint 负责提供字节流给 Processor,Processor 负责提供 Tomcat Request 对象给 Adapter,Adapter 负责提供 ServletRequest 对象给容器。这样功能层次明确的实现了低耦合、高内聚的内部功能。

  而至于为什么将Endpoint 和 Processor 放在一起抽象成ProtocolHandler 组件是因为Tomcat的

  I/O 模型和应用层协议可以自由组合,比如 NIO + HTTP 或者 NIO.2 + AJP。所以设计者们将网络通信和应用层协议放在一起考虑,最终设计了ProtocolHandler接口来封装这两种变化点。各种协议和通信模型的组合有相应的具体实现类。比如:Http11NioProtocol 和AjpNioProtocol。

  除了这些变化点,系统也存在一些相对稳定的部分,因此 Tomcat 设计了一系列抽象基类来封装这些稳定的部分,抽象基类 AbstractProtocol 实现了 ProtocolHandler 接口。每一种应用层协议有自己的抽象基类,比如 AbstractAjpProtocol 和 AbstractHttp11Protocol,具体协议的实现类扩展了协议层抽象基类。

它们的继承关系:

                                                                      Tomcat的连接器-Coyote-编程部落

ProtocolHandler组件

  连接器的ProtocolHandler是用于处理网络连接和应用层协议的,其包含了两个组件:Endpoint 和 Processor。

Endpoint

  Endpoint 是通信端点,即通信监听的接口,是具体的 Socket 接收和发送处理器,是对传输层的抽象Endpoint 是一个接口,对应的抽象实现类是 AbstractEndpoint,而 AbstractEndpoint 的具体子类,比如在 NioEndpoint 和 Nio2Endpoint 中,有两个重要的子组件:Acceptor 和 SocketProcessor。其中 Acceptor 用于监听 Socket 连接请求。SocketProcessor 用于处理接收到的 Socket 请求,它实现 Runnable 接口,在 run 方法里调用协议处理组件 Processor 进行处理。为了提高处理能力,SocketProcessor 被提交到线程池来执行。而这个线程池叫作执行器(Executor).

Processor 

  Processor 是对应用层协议的抽象。Processor 是一个接口,定义了请求的处理等方法。它的抽象实现类 AbstractProcessor 对一些协议共有的属性进行封装,没有对方法进行实现。具体的实现有 AjpProcessor、Http11Processor 等,这些具体实现类实现了特定协议的解析方法和请求处理方式。

                   Tomcat的连接器-Coyote-编程部落

  从图中看到,Endpoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。到这里我们学习了 ProtocolHandler 的总体架构和工作原理,关于 Endpoint 的详细设计,后面我还会专门介绍 Endpoint 是如何最大限度地利用 Java NIO 的非阻塞以及 NIO.2 的异步特性,来实现高并发。

Adapter 组件

  由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat 定义了自己的 Request 类来“存放”这些请求信息。ProtocolHandler 接口负责解析请求并生成 Tomcat Request 类。但是这个 Request 对象不是标准的 ServletRequest,也就意味着,不能用 Tomcat Request 作为参数来调用容器。Tomcat 设计者的解决方案是引入 CoyoteAdapter,这是适配器模式的经典运用,连接器调用 CoyoteAdapter 的 sevice 方法,传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方法。