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 包含多个上下文。
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"/>在 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(); }