2020-heibaiying-Tomcat 架构解析
Tomcat 架构解析
一、Tomcat 简介
- Tomcat 7:支持
Servlet 3.0 ,JSP 2.2,EL 2.2 和WebSocket 1.1 规范。 - Tomcat 8.5:支持
Servlet 3.1 ,JSP 2.3,EL 3.0 和WebSocket 1.1 规范,并可以通过安装Tomcat 原生库来支持HTTP/2 。当前Tomcat 8.5 已经完全取代了Tomcat 8 ,Tomcat 8 已停止维护,并不再提供下载。 - Tomcat 9:是当前主要的发行版;它建立在
Tomcat 8.0.x 和8.5.x 之上,并实现了Servlet 4.0 ,JSP 2.3,EL 3.0,WebSocket 1.1 和JASPIC 1.1 规范。 - Tomcat 10 (alpha) :是当前主要的开发版;它实现了
Servlet 5.0 ,JSP 3.0,EL 4.0 和WebSocket 2.0 规范。
二、Tomcat 架构

- Server:表示整个
Servlet 容器,在整个Tomcat 运行环境中只有唯一一个Server 实例。一个Server 包含多个Service ,每个Service 互相独立,但共享一个JVM 以及系统类库。 - Service:一个
Service 负责维护多个Connector 和一个Engine 。其中Connector 负责开启Socket 并监听客户端请求,返回响应数据;Engine 负责具体的请求处理。 - Connector:连接器,用于监听并转换来自客户端
Socket 请求,然后将Socket 请求交由Container 处理,支持不同协议以及不同的I/O 方式。 - Engine:表示整个
Servlet 引擎,在Tomcat 中,Engine 为最高层级的容器对象。 - Host:表示
Engine 中的虚拟机,通常与一个服务器的网络名有关,如域名等。 - Context:表示
ServletContext ,在Servlet 规范中,一个ServletContext 即表示一个独立的Web 应用。 - Wrapper:是对标准
Servlet 的封装。
以上各组件的详细介绍如下:
三、连接器
连接器的主要功能是将

3.1 ProtocolHandler
1. Endpoint
- BIO:即最传统的
I/O 方式; - NIO:采用
Java NIO 类库进行实现,Tomcat 8 之后默认该I/O 方式,以替换原来的BIO ; - NIO2:采用
JDK 7 最新的NIO2 类库进行实现; - APR:采用
APR (Apache 可移植运行库) 实现,APR 是使用C/C++ 编写的本地库,需要单独进行安装。
2. Processor
负责构造
HTTP / 1.1 协议;HTTP / 2.0 协议:自Tomcat 8.5 以及9.0 版本后开始支持;AJP 协议:即定向包协议。
3. ProtocolHandler

可以看到上面的
3.2 Adapter

3.3 Mapper 和MapperListener
由
四、容器
4.1 Container 和Lifecycle
init()
,start()
,stop()
,destroy()
:

4.2 分层结构
- Engine:最顶层的容器,一个
Service 中只有一个Engine ; - Host:代表一个虚拟主机,一个
Engine 可以包含多个虚拟主机; - Context:表示一个具体的
Web 应用程序,一个虚拟主机可以包含多个Context ; - Wrapper:是
Tomcat 对Servlet 的包装,一个Context 中可以有多个Wrapper 。

server.xml
配置文件中也有体现:
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
</Engine>
</Service>
</Server>
这里的
4.3 Pipeline 和Valve

由连接器发过来的请求会最先发送到
public interface Pipeline extends Contained {
public Valve getBasic(); // 获得Basic Valve
public void setBasic(Valve valve); // 设置Basic Valve
public void addValve(Valve valve); // 新增Valve
public Valve[] getValves(); // 获取所有Valve
public void removeValve(Valve valve);// 移除Valve
public Valve getFirst(); //获取第一个 Valve
public boolean isAsyncSupported();
public void findNonAsyncValves(Set<String> result);
}
public interface Valve {
public Valve getNext();
// 每一个Valve都持有其下一个Valve,这是标准的责任链模式
public void setNext(Valve valve);
// 对请求进行检查、处理或增强
public void invoke(Request request, Response response) throws IOException, ServletException;
public void backgroundProcess();
public boolean isAsyncSupported();
}
通过
public class StandardEngine extends ContainerBase implements Engine {
public StandardEngine() {
super();
pipeline.setBasic(new StandardEngineValve());
....
}
}
在
final class StandardEngineValve extends ValveBase {
public StandardEngineValve() {super(true);}
@Override
public final void invoke(Request request, Response response) throws IOException, ServletException {
// 获取当前请求的Host
Host host = request.getHost();
if (host == null) {
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(host.getPipeline().isAsyncSupported());
}
// 将请求传递给host的Pipeline的第一个Valve
host.getPipeline().getFirst().invoke(request, response);
}
}
invoke
方法中会获取到下一级容器(Host)的第一个
4.4 FilterChain
通过invoke
方法中为该请求创建
// 为该请求创建Filter Chain
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
.....
// 调用Filter Chain的doFilter方法
filterChain.doFilter(request.getRequest(), response.getResponse());
当到达执行链的末端后,会执行
servlet.service(request, response);
以我们最常使用的
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
.....
doGet(req, resp);
} else {
......
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} ......
}
至此,来自客户端的请求就逐步传递到我们编写的
五、请求流程
这里对前面的连接器和容器章节进行总结,

六、启动流程

1. startup.sh & catalina.sh
startup.sh
是对 catalina.sh
的一层薄封装,主要用于检查 catalina.sh
是否存在以及调用它。 catalina.sh
负责启动一个
2. Bootstrap
bin
目录下,主要负责初始化
3. Catalina
七、类加载器

1. Web App Class Loader
负责加载 /WEB-INF/classes
目录下的未压缩的/WEB-INF/lib
目录下的
2. Shared Class Loader
是所有
3. Catalina Class Loader
用于加载
4. Common Class Loader
其作用和
参考资料
- 刘光瑞
. Tomcat 架构解析. 人民邮电出版社. 2017-05