04 Tomcat 连接器 Coyote
Coyote 工作原理
Coyote 是Tomcat的连接器框架的名称 , 是Tomcat服务器提供的供客户端访问的外部接口。客户端通过Coyote与服务器建立连接、发送请求并接受响应 。
Coyote 封装了底层的网络通信(Socket 请求及响应处理),为Catalina 容器提供了统一的接口,使Catalina 容器与具体的请求协议及IO操作方式完全解耦。
Coyote 将Socket 输入转换封装为 Request 对象,交由Catalina容器进行处理,处理请求完成后, Catalina 通过Coyote 提供的Response 对象将结果写入输出流 。
Coyote 作为独立的模块,只负责具体协议和IO的相关操作, 与Servlet 规范实现没有直接关系,因此即便是 Request 和 Response 对象也并未实现Servlet规范对应的接口, 而是在Catalina 中将他们进一步封装为ServletRequest 和 ServletResponse 。
Coyote 的 IO模型与协议
在Coyote中 , Tomcat支持的多种I/O模型和应用层协议,具体包含哪些IO模型和应用层 协议,参考如下。
Tomcat 支持的IO模型
Tomcat 支持的IO模型:自8.5/9.0 版本起,Tomcat 移除了 对 BIO 的支持.
传输层协议
IO模型 | 描述 |
---|---|
NIO | 非阻塞I/O,采用Java NIO类库实现。 |
NIO2 | 异步I/O,采用JDK 7最新的NIO2类库实现。 |
APR | 采用Apache可移植运行库实现,是C/C++编写的本地库。如果选择该方案,需要单独安装APR库。 |
Tomcat 支持的应用层协议
应用层协议 | 描述 |
---|---|
HTTP/1.1 | Web应用采用的访问协议 |
AJP | 用于和Web服务器集成(如Apache),以实现对静态资源的优化以及集群部署,当前支持AJP/1.3。 |
HTTP/2 | HTTP 2.0大幅度的提升了Web性能。下一代HTTP协议 , 自8.5以及9.0版本之后支持。 |
在 Tomcat8.0 之前 ,Tomcat 默认采用的I/O方式为 BIO , 之后改为 NIO。 无论 NIO、NIO2还是 APR, 在性能方面均优于以往的BIO。
Tomcat为了实现支持多种I/O模型和应用层协议,一个容器可能对接多个连接器, 如下图:
单独的连接器或者容器都不能对外提供服务,需要把它们组装 起来才能工作,组装后这个整体叫作Service组件。
Service本身只是把连接器和容器组装在一起。
Tomcat内可能有多个Service,这样设计更灵活性。
通过在Tomcat中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。
连接器Coyote 中的组件
EndPoint 通信监听的接口
EndPoint : Coyote 通信端点,即通信监听的接口,是具体Socket接收和发送处理器,是对传输层的抽象,因此EndPoint用来实现TCP/IP协议的。
Tomcat 并没有EndPoint 接口,而是提供了一个抽象类AbstractEndpoint (NioEndpoint ,Nio2Endpoint ,AprEndpoint 都继承了AbstractEndpoint)
其内定义了两个内部类:Acceptor和SocketProcessor。
-
Acceptor用于监听Socket连接请求。
-
SocketProcessor用于处理接收到的Socket请求,它实现Runnable接口,在Run方法里 调用协议处理组件Processor进行处理。为了提高处理能力,SocketProcessor被提交到线程池来执行。而这个线程池叫作执行器(Executor)。
Executor也是一个知识点,后面阐述 Tomcat如何扩展原生的Java线程池
Processor :Coyote 协议处理接口
Processor :Coyote 协议处理接口 。EndPoint是用来实现TCP/IP协议;Processor用来实现HTTP协议。
Processor接收来自EndPoint的Socket,读取字节流解 析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理, Processor是对应用层协议的抽象。
ProtocolHandler : Coyote 协议接口
ProtocolHandler: Coyote 协议接口, 通过Endpoint 和 Processor , 实现针对具体协议的处理能力。
Tomcat 按照协议和I/O 提供了6个实现类 :
- AjpNioProtocol
- AjpAprProtocol
- AjpNio2Protocol
- Http11NioProtocol
- Http11Nio2Protocol
- Http11AprProtocol
配置tomcat/conf/server.xml 时 , 至少要指定具体的 ProtocolHandler , 当然也可以指定协议名称 , 如 : HTTP/1.1 ,如果安装了APR,那么将使用Http11AprProtocol , 否则使用 Http11NioProtocol 。
通过Service标签中连接器Connector 的属性 protocol="HTTP/1.1 指定协议名称
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector protocol="AJP/1.3"
address="::1"
port="8009"
redirectPort="8443" />
</Service>
Adapter 负责Request、ServletRequest对象的转换
由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的Request类来“存放”这些请求信息。
ProtocolHandler接口负责解析请求并生成Tomcat的Request类。 但是这个Request对象不是标准的ServletRequest,也就意味着,不能用Tomcat Request作为参数来调用容器。
Tomcat设计者的解决方案是引入CoyoteAdapter,这是适配器模式的经典运用,连接器调用CoyoteAdapter的Sevice方法,传入的是Tomcat Request对象,CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调用容 器的Service方法。