此系列是结合Tomcat使用来解读Tomcat源码的专栏,主要参数材料为Tomcat源码和《深入剖析Tomcat》这本书。《深入剖析Tomcat》这本书挺老了,讲的也是Tomcat4和5,但是对应Tomcat整体体系结构和内部实现原理讲的比较深入,仍然是必读的解读Tomcat的书籍。
笔者不会完全按照这本书的目录解读,会做一些内容上的删减,比如”日志”、”安全性”、”部署器”、”Manager”、”JMX”等章节,读者若对其感兴趣请参数书籍和官网文档去了解。
然后笔者在书籍选择会偏向选择美国的相关书籍,毕竟计算机行业是从美国发展起来的。
本系列初步的目录如下:
1.整体架构:简单入门、Web和Servlet、整体架构、核心流程
2.Tomcat启动流程:启动流程、类加载、各级组件/容器初始化和启动
3.服务器Server
4.服务Service
5.连接器Connector和线程池
6.容器Container:Host、Engine、Context、Wrapper
7.Http请求处理流程上:调试追踪一个HTTP请求的处理过程
8.http请求处理流程下:调试追踪一个HTTP请求的处理过程
本系列的源码工程为:HowTomcatWorksSourceCode。
本文目录为:
一、简单使用
使用Tomcat可以通过单独的SpringMVC的Web项目启动,或者通过SpringBoot启动tomcat。
单独使用主要是配置Servlet:
<servlet>
<servlet-name>springmvc-demo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc-demo</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
通过SpringBoot启动则主要是引入WEB(tomcat)的starter。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
然后则可以通过浏览器或Http Client发送HTTP请求,这里不再赘述了。
二、Tomcat和Servlet
Tomcat是什么?Tomcat是Web服务器、Servlet容器。我们谈及Web服务器并不是特指的是HTTP Web Server,WEB服务器本身不是只支持HTTP协议请求的。
Tomcat自身是使用Java开发的,实现了Servlet标准。Servlet是Java处理Web请求的顶层API,接受和处理Web请求。
我们看下官方的注释:
* A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web
* clients, usually across HTTP, the HyperText Transfer Protocol.
HttpServlet是继承自Servlet,这表面Servet本身不是特指HTTP协议请求的处理API。
Wiki对Tomcat的说明是”Tomcat是实现Servlet、WebSocket标准的开源Java Web服务器,通常指的是处理HTTP协议的WEB服务器”。
三、整体架构
要分析Tomcat的整体架构可以从启动方法开始研究。
分析流程是:Bootstrap—>Catalina—->Server—->Service—>Engine–>Container—->Host—>Context—>Wrapper—>Servlet这个源码方向。
一个Tomcat启动的Server服务器只有一个,而有多个Service服务。executors线程池、connectors连接器(列表)也是由一个StandardService(Service)创建的。
Engine、Container、Host、Context、Wrapper都称为”容器”,容器类的类继承关系图如下:
Connectors连接器是连接Service和Container的结构,Connectors会创建和启动protocolHandler协议处理器用以处理http、ajp、https协议。
Tomcat整体的架构,笔者在网上找到这个图总结的比较好的:
四、核心流程
4.1 初始化和启动流程
启动流程可以从Bootstrap启动类开始解读,一步一步来到Context,最后来到Wrapper和Servlet。 启动流程如下,都是先初始化和启动父容器再初始化和启动子容器。
需要注意这段代码:
// Start our child containers, if any
Container[] children = findChildren();
List<Future<Void>> results = new ArrayList<>(children.length);
for (Container child : children) {
results.add(startStopExecutor.submit(new StartChild(child)));
}
MultiThrowable multiThrowable = null;
for (Future<Void> result : results) {
try {
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
multiThrowable.add(e);
}
}
这里是启动线程池去启动子容器children,父容器在阻塞等待子容器的启动结果。
4.2 Http请求处理流程
我们之前分析DispatchServlet知道DispatchServlet实现了Servlet接口,并将service方法转发到dispatch方法。但DispatchServlet的创建、初始化、销毁都是Servlet容器(如Tomcat)来操作的。
Servlet#service方法也是由Tomcat调用的,上面启动流程中Wrapper将Servlet修饰为StandardWrapper。
/**
* The (single) possibly uninitialized instance of this servlet.
*/
protected volatile Servlet instance = null;
StandardWrapper是Servlet的修饰器,我们可以从Servlet的service方法解读引用流程。
Http请求的基本流程如下,后续笔者会跟踪源码流程给出Http请求处理的流程解读。
五、参考材料
- https://tomcat.apache.org/tomcat-10.1-doc/index.html
- 《深入剖析Tomcat》
- 《HTTP权威指南》