5. Tomcat 中的 NIO 应用

it2022-05-05  160

5. Tomcat 中的 NIO 应用

5.1. Tomcat 核心架构


Tomcat 是一个 apache 推出的一个 web 应用服务器,核心功能就是解析 Http协议,处理网络 IO 操作,执行 Servlet 对象,其简易架构如下:

其中:

1) Server:代表整个容器,它可能包含一个或多个 Service 和全局的对象资源;2) Service:包含一个或多个 Connector 和一个 Engine,这些 Connector和 Engine 相关联;3) Connector:处理与客户端的通信,网络 I/O 操作;4) Engine:表示请求处理流水线(pipeline),它接收所有连接器的请求,并将响应交给适当的连接器返回给客户端;5) Host:网络名称(域名)与 Tomcat 服务器的关联,默认主机名 localhost,一个 Engine 可包含多个 Host;6) Context:表示一个 Web 应用程序,一个 Host 包含多个上下文。

 

5.2. Tomcat 中的 NIO 应用配置


Tomcat 中的 NIO 应用要从 Connector 说起,Connector 是请求接收环节与请求处理环节的连接器。具体点说,就是 Connector 将接收到的请求传递给Tomcat 引擎(Engine)进行处理,引擎处理完成以后会交给 Connector 将其响应到客户端。但是 Connector 本身并不会读写网络中的数据,读写网络中的数据还是要基于网络 IO 进行实现。但使用哪种 IO 模型需要由 Connector 对象进 行指定。 例如:可在 tomcat 的 server.xml 进行配置,其默认配置如下:

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

一个 Tomcat 中可以配置多个 Connector,分别用于监听不同端口,或处理不同协议,在如上配置中 Connector 使用的协议默认为”HTTP/1.1”,系统底层会基于此配置,通过反射创建 Http11NioProtocol 对象,而此对象底层就是基于NIO 中的 IO 多路复用技术实现网路数据读写的。假如希望使用其它协议或 NIO方式可以修改其默认配置。例如:我们配置 NIO 中的异步应用模型。

<Connector connectionTimeout="20000" port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol" redirectPort="8443"/>

5.3. Tomcat 中的 NIO 应用设计


在 tomcat 中,目前 IO 模型的最佳应用模式还是 IO 多路复用,因为 BIO 的缺点在于不管当前连接有没有数据传输,它始终阻塞占用线程池内的一个线程,而NIO 的处理方式是若通道无数据可读取,此时线程不阻塞直接返回,可用于处理其他连接,提高了线程利用率。其工作模型大致如下:

1) Acceptor 以阻塞模式接收 TCP 连接,然后对连接信息进行封装并以事件方式注册(register)到 Poller 上;2) Poller 进行事件迭代,循环执行 selector.select(xxx),如果有通道readable,那么在 processKey 方法中交给 worker 线程池中的线程处理。

说明:假如想在 maven 项目中想对 tomcat 的源码进行快速分析,可先添加如下依赖,基于此依赖可借助 maven 对 tomcat 源码进行组织。

<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>9.0.6</version> </dependency>

基于 tomcat 依赖编写如下代码启动 tomcat,进行 debug 分析

public static void main(String[] args)throws Exception { //1.构建tomcat对象 Tomcat tomcat = new Tomcat(); //2.构建connector对象,并指定协议 //tomcat实用connector处理链接,一个tomcat可以配置多个connector Connector connector = new Connector("HTTP/1.1"); //3.设置tomcat舰艇端口 connector.setPort(8080); tomcat.setConnector(connector); //启动tomcat tomcat.start(); tomcat.getServer().await(); }

 


最新回复(0)