你的老朋友Tomcat😺(二)Tomcat的主体功能架构

991

上一篇简单介绍了什么是Tomcat以及Web应用,这次介绍Tomcat是如何实现它的功能,整体架构是什么样子的。

一、编译Tomcat源码

  1. 准备好JDK8以上和maven环境。
  2. 官网下载源码包(tomcat9.0.36版本)
  3. 解压到自己指定的目录,这里我的目录是/Users/mc/Documents/workspace/tomcat9,然后进入apache-tomcat-9.0.36-src目录下新建一个home目录,将目录下的conf、 webapps文件夹移动至home目录下。
  4. 将项目导入IDEA,在tomcat9目录和apache-tomcat-9.0.36-src目录下分别新建pom.xml文件。
  5. 设置启动类为org.apache.catalina.startup.Bootstrap和VM options参数,启动之后访问localhost:8080

💡:上述步骤完成之后启动还会有一些问题,解决方案和具体配置信息可以参考我已经编译好的项目debug-tomcat9,这里不再赘述。

在上一篇介绍了 Tomcat 的主要功能是 HTTP 服务器 + Servlet 容器,也就是: 1、处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。2、加载和管理 Servlet,以及具体处理 Request 请求。 在 Tomcat 中设计了两个组件连接器 Connector 和容器 Container 来实现这两个功能

二、连接器

2.1 Connector整体结构

在Connector中有两个比较重要的组件:

/**
 * Coyote protocol handler.
 */
protected final ProtocolHandler protocolHandler;


/**
 * Coyote adapter.
 */
protected Adapter adapter = null;
  • ProtocolHandler是用来抽象协议的接口,它的继承关系如下:
    它的通用实现抽象类是AbstractProtocol,在AbstractProtocol中有三个重要的组件AbstractEndpoint、Processor、Adapter(是由Connector传入的),它们的作用分别是用来实现网络通信、应用层协议解析、将Tomcat的Request/Response与 ServletRequest/ServletResponse进行转化。ProtocolHandler的子类即是各种协议和通信模型的组合相应的具体实现类,Http2相关的组合则是由另外的接口Http2Protocol及子类实现。
  • Adapter:适配器组件,由于协议不同导致请求信息不同,Tomcat定义了自己的Request类来存储请求信息。ProtocolHandler接口负责解析请求并生成Tomcat Request类。但是这个Request对象不是标准的ServletRequest,所以引入CoyoteAdapter,连接器调用 CoyoteAdapter的sevice 方法,传入Tomcat Request对象,CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调用容器
 @Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
        throws Exception {

    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);
    ……
    ……
}

这里涉及到的I/O模型有三种:

  • NIO:非阻塞 I/O
  • NIO.2:异步 I/O
  • APR:采用Apache可移植运行库实现,是C/C++编写的本地库

支持的应用层协议:

  • HTTP/1.1:大部分Web应用采用的访问协议
  • HTTP/2:HTTP2.0大幅度的提升了Web性能
  • AJP:用于和Web服务器集成如Apache

具体实现可能不同,但是整体的流程是一致的,AbstractEndpoint负责处理网络请求提供字节流给Processor,Processor负责解析应用层协议提供Tomcat Request对象给Adapter,Adapter负责将Tomcat Request对象转换为ServletRequest对象调用容器。

2.2 ProtocolHandler组件

  • AbstractEndpoint:是一个抽象类,对传输层协议的抽象,是具体的Socket接收和发送处理器。而AbstractEndpoint的具体子类,比如在NioEndpoint和Nio2Endpoint 中,有两个重要的子组件:Acceptor(在AbstractEndpoint中,Nio2Endpoint也有自己的实现)和SocketProcessor。Acceptor用于监听Socket连接请求,SocketProcessor用于处理接收到的Socket请求。

  • Processor:是对应用层协议的抽象,Processor接收来自Endpoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理,它的抽象实现类AbstractProcessor对一些协议共有的属性进行封装,具体的实现有AjpProcessor、Http11Processor等实现了特定协议的解析方法和请求处理方式。

三、容器

容器就是用来装载Servlet的,在Tomcat中有四种容器:Engine、Host、Context、Wrapper,它们之间是采用组合模式的父子关系Engine(Host(Context(Wrapper)))。Engine表示引擎用来管理多个虚拟站点,一个Service最多只能有一个Engine。Host代表的是一个虚拟站点,可以给Tomcat配置多个虚拟主机地址,而一个虚拟站点下可以部署多个Web应用程序;Context表示一个Web应用程序;Wrapper表示一个Servlet;

Tomcat是用Mapper组件来确定请求由哪个Wrapper容器里的Servlet来处理请求的。Mapper组件的功能是将用户请求的URL定位到一个Servlet,它保存了容器组件与访问路径的映射关系:Host容器里配置的域名、Context容器里的Web应用路径、Wrapper容器里Servlet映射的路径,可以理解为这些配置信息就是一个多层次Map(由Mapper中的hosts、ContextVersion中的几个Wrappers等组成)。当一个请求到来时,Mapper组件通过解析请求URL里的域名和路径到Map里去查找定位到一个Servlet。

四、整体结构