Connector 属于 StandardService 里的一个组件,可以在 server.xml 中配置,指定协议、端口、超时时间等。
<?xml version="1.0" encoding="UTF-8"?>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
</Service>
每个 Service 里可以配置多个 Connector。
Tomcat 的 Connector 支持两种协议,HTTP 和 AJP。
关于这两种协议,官方文档是这样说的
- The HTTP connector is setup by default with Tomcat, and is ready to use. This connector features the lowest latency and best overall performance.*
- When using a single server, the performance when using a native webserver in front of the Tomcat instance is most of the time significantly worse than a standalone Tomcat with its default HTTP connector, even if a large part of the web application is made of static files. If integration with the native webserver is needed for any reason, an AJP connector will provide faster performance than proxied HTTP. AJP clustering is the most efficient from the Tomcat perspective. It is otherwise functionally equivalent to HTTP clustering.*
通过配置不同的 protocol 属性,可以使用不同的 ProtocalHandler。
配置HTTP/1.1时,默认会使用 org.apache.coyote.http11.Http11NioProtocol。也可以通过指定类名的方式来配置,比如 protocol=”org.apache.coyote.http11.Http11Nio2Protocol”
。
针对 HTTP 和 AJP 两种协议,都有 BIO/NIO/NIO2/APR 四种处理方式。
- HTTP
- org.apache.coyote.http11.Http11Protocol
- org.apache.coyote.http11.Http11NioProtocol
- org.apache.coyote.http11.Http11Nio2Protocol
- org.apache.coyote.http11.Http11AprProtocol
- AJP
- org.apache.coyote.http11.Ajp11Protocol
- org.apache.coyote.http11.Ajp11NioProtocol
- org.apache.coyote.http11.Ajp11Nio2Protocol
- org.apache.coyote.http11.Ajp11AprProtocol
AJP 的处理我并没有去细看,但大的代码结构基本和 HTTP 的处理类似。
后面重点看下 HTTP 1.1 连接的几种处理方式(我看的这个版本还不支持Http 2.0)。
HTTP BIO,同步阻塞
使用的是Java BIO 技术,一个 Acceptor 线程负责创建连接,把建立好连接的 socket 给到 SocketProcessor, 然后把SocketProcessor 丢到线程池里去执行。经过一系列处理后最终到达 CoyoteAdapter。
线程模型即:
- Acceptor: 单线程
- SocketProcessor:线程池
HTTP NIO, 同步非阻塞
使用的是Java NIO 技术,一个 Acceptor 线程负责创建连接,把建立好连接的 socket 交给 一个Poller. 这里有多个Poller,每个Poller一个线程。
Poller 负责把 socket 注册到 selector, 负责轮询 selector, 有数据可读的时候,就交给SocketProcessor丢到线程池里去执行。经过一系列处理后最终到达 CoyoteAdapter。
线程模型即:
- Acceptor: 单线程
- Poller:多个线程
- SocketProcessor: 线程池
HTTP NIO2,异步非阻塞
使用的是 Java NIO2(AIO) 技术,一个 Acceptor 线程(代码里 Acceptor 只支持创建多个的,通过变量 acceptorThreadCount 来控制)负责创建连接,把建立好连接的 socket 给到 SocketProcessor,然后把SocketProcessor 丢到线程池里去执行。
线程模型即:
- Acceptor: 单线程
- SocketProcessor: 线程池
是不是看起来和 HTTP BIO 很像,但是这里的 read/write 用的是 NIO2 的异步非阻塞方式,即read的时候带个callback,等有OS有数据了,再来回调你的处理方法,效率比 BIO 高很多。
HTTP APR
在新的 Tomcat 10.1.x 的后续版本将会被丢弃。
代码结构
如前面几张图所示,整个连接器的代码结构还是很清晰的。在 Tomcat 启动的时候,通过 Digest 解析 server.xml 配置的时候,会在 StandardService 里创建一些 Connector。
Connector 也是实现生命周期接口的,在 StandardService 初始化和启动的时候,Connector 也会完成自己的初始化和启动操作,启动过程中,EndPoint 会去完成 bind 操作,然后启动 accept 线程。
ProtocalHandler、EndPoint、ConnectionHandler、Processor、Adaptor 这几个角色互相配合,完成各自的工作。