Tomcat架构深度解析:从Server到Servlet的全流程揭秘
第一章:Tomcat架构概述
1.1 Tomcat的角色与定位:Web服务器 vs Servlet容器
Tomcat 是什么?它既是一种轻量级 Web 服务器,也是一种符合 Java EE 规范的 Servlet 容器。
-
Web服务器:类似 Nginx、Apache HTTP Server,处理静态资源请求(如 HTML、CSS、JS)。
-
Servlet容器:它能解析 Java Web 应用,执行 Servlet 逻辑,是 J2EE 架构中的核心组件。
Tomcat 专注于 Servlet/JSP 执行环境,是大多数 Java Web 项目的默认运行平台。你可以理解为:
🧠 “Nginx 负责搬运砖(静态内容),而 Tomcat 负责烧菜(动态内容)。”
1.2 核心功能:网络连接器(Connector)与Servlet容器(Container)
Tomcat 架构的设计核心是 分离连接(Connector)与处理(Container)。
-
Connector 负责“接收请求”:它监听端口、解析协议(如 HTTP/AJP),把原始 Socket 请求转换成 Java 对象(如
ServletRequest)。 -
Container 负责“处理请求”:它解析 URL、找到对应的 Servlet、执行业务逻辑并返回响应。
两者通过 Service 组件进行绑定,形成完整的请求处理路径。
1.3 架构图描述(文字形式)
用文字描述 Tomcat 的核心架构图,帮助建立层级结构的直观印象:
┌────────────────────┐
│ Server │ ← Tomcat 最顶层组件,负责整体生命周期
└────────┬───────────┘
│
┌─────▼─────┐
│ Service │ ← 每个 Server 可包含多个 Service
└─────┬─────┘
│
┌───────▼────────┐
│ Connector │ ← 监听端口,接收并转换 HTTP/AJP 请求
└────────┬───────┘
│
┌───────▼────────────┐
│ Engine │ ← 请求处理的核心入口,属于 Container
└──────┬─────────────┘
│
┌─────▼─────┐
│ Host │ ← 虚拟主机,用于支持多域名部署
└─────┬─────┘
│
┌────▼─────┐
│ Context │ ← 每个 Web 应用一个 Context(对应一个 WAR 包)
└────┬─────┘
│
┌───▼────┐
│Wrapper │ ← 每个 Servlet 一个 Wrapper,最终执行点
└────────┘
从上图可见,请求从最底层的 Connector 发起,最终由 Wrapper 调用 Servlet 实现类处理业务逻辑。这就是 Tomcat 的核心处理链路。
第二章:核心组件详解
2.1 Server组件:管理Tomcat实例的生命周期
Server 是 Tomcat 的顶级组件,代表整个 Tomcat 实例,它的职责是控制整个服务的生命周期。
-
代表类:
org.apache.catalina.core.StandardServer -
主要职责:
-
统一管理所有
Service。 -
监听
SHUTDOWN命令端口(默认8005),优雅关闭。 -
触发
init(),start(),stop()生命周期方法。
-
💡 类比理解:
Server 就像是一个酒店的总经理,下面每个 Service 是一个功能部门,比如前台、后厨、客房管理。
🔍 架构图描述(Server层):
┌────────────────────┐
│ Server │
│ 监听8005关闭端口 │
│ 管理多个Service │
└────────┬───────────┘
↓
[多个Service]
2.2 Service组件:整合Connector与Engine
Service 是连接请求(Connector)和业务处理(Engine)的桥梁。
-
代表类:
org.apache.catalina.core.StandardService -
主要职责:
-
一个 Service 包含:
-
一个 Engine(处理业务逻辑)
-
一个或多个 Connector(接收外部请求)
-
-
多个 Connector 可以绑定同一个 Engine,实现多协议共享逻辑处理。
-
💡 类比理解:
Service 就像酒店里的“接待部门”:门童(Connector)负责迎客,带到接待柜台(Engine)处理入住流程。
🔍 架构图描述(Service层):
┌──────────────────────────┐
│ Service │
│ ┌─────────────────────┐ │
│ │ Engine │ │ ← 业务处理核心
│ └─────────────────────┘ │
│ ┌────────────┐ ┌────────────┐
│ │ Connector1 │ │ Connector2 │ ← 多个端口或协议接入
│ └────────────┘ └────────────┘
└──────────────────────────┘
2.3 Connector组件:协议解析与请求转发
Connector 负责与客户端打交道,是 Tomcat 与外部世界的接口。
-
代表类:
org.apache.coyote.http11.Http11NioProtocol -
职责:
-
监听指定端口(如 8080)。
-
解析 HTTP 或 AJP 协议,转换为 Request/Response 对象。
-
将请求传入对应的 Engine 继续处理。
-
🌐 支持的协议实现:
| 模式 | 类名 | 特点 |
|---|---|---|
| BIO | Http11Protocol | 同步阻塞,低性能 |
| NIO | Http11NioProtocol | 异步非阻塞,推荐 |
| APR | Http11AprProtocol / AjpAprProtocol | 高性能,依赖本地库 |
| NIO2 | Http11Nio2Protocol | NIO 的改进版 |
🧪 示例:配置 NIO Connector(在server.xml中)
2.4 Container组件:Servlet容器的分层结构
Container 是 Tomcat 的核心处理器,负责执行 Servlet 逻辑。
它包含 4 层结构,层层包裹,类似俄罗斯套娃:
| 层级 | 代表类 | 作用 |
|---|---|---|
| Engine | StandardEngine | Service 中唯一的业务处理容器 |
| Host | StandardHost | 虚拟主机,支持多域名部署 |
| Context | StandardContext | 一个 Web 应用对应一个 Context |
| Wrapper | StandardWrapper | 每个 Servlet 一个 Wrapper |
💡 类比理解:
Container 像一栋办公楼:
Engine 是大楼
Host 是楼层(不同租户)
Context 是部门
Wrapper 是员工(Servlet)
🔍 架构图描述(Container层):
Engine
└── Host (域名)
└── Context (Web应用)
└── Wrapper (Servlet)
✅ 本章小结
-
Server 管理整个 Tomcat 实例生命周期。
-
Service 是连接外部请求(Connector)与内部业务(Engine)的桥梁。
-
Connector 接收客户端请求并解析协议。
-
Container 是核心执行单元,包含 Engine → Host → Context → Wrapper 四级结构。
第三章:请求处理流程
3.1 请求到达 Connector 的流程(Socket → ServletRequest)
-
浏览器发送 HTTP 请求
例如访问http://localhost:8080/demo/hello,TCP 三次握手后,请求数据会到达 Tomcat 监听的端口(默认 8080)。 -
Connector 接收请求
-
对应类:
org.apache.coyote.http11.Http11NioProtocol -
监听线程(Acceptor)接收连接请求,并交给 Poller 线程注册到 Selector(NIO 模型)。
-
-
协议解析
-
使用
Http11Processor解析 HTTP 协议。 -
将解析结果封装成
org.apache.coyote.Request和org.apache.coyote.Response对象。
-
-
适配成 Servlet API
-
CoyoteAdapter将底层 Request/Response 转换为HttpServletRequest和HttpServletResponse,进入容器处理流程。
-
🔍 流程图(文字版):
浏览器 → TCP连接 → Connector监听端口
↓
Acceptor线程接收连接
↓
Poller/Processor解析HTTP
↓
封装为Request/Response
↓
CoyoteAdapter适配到Servlet API
3.2 Mapper组件的URL映射机制
Mapper 的作用是根据 URL 找到正确的 Servlet。
-
匹配规则(从粗到细):
-
匹配 Host(域名)
-
匹配 Context(Web 应用路径)
-
匹配 Wrapper(Servlet 映射规则)
-
例如访问 http://localhost:8080/demo/hello:
-
Host:
localhost -
Context:
/demo -
Wrapper:匹配到
/hello的 Servlet
关键类:
-
org.apache.catalina.mapper.Mapper -
org.apache.catalina.core.StandardHost -
org.apache.catalina.core.StandardContext
3.3 Pipeline-Valve机制:请求过滤与处理链
Tomcat 的容器(Engine、Host、Context、Wrapper)都有一个 Pipeline(管道),里面装着多个 Valve(阀门)。
-
Pipeline:请求处理的有序链路。
-
Valve:具体的处理步骤,例如日志记录、安全检查、压缩等。
-
基本原则:请求会沿着 Valve 链从上到下传递,最终交给 Servlet 处理。
示例:默认Valve链
EnginePipeline
→ HostPipeline
→ ContextPipeline
→ WrapperPipeline
→ StandardWrapperValve(最终调用Servlet.service())
可自定义Valve示例:
public class MyLogValve extends ValveBase {
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
System.out.println("请求URI: " + request.getRequestURI());
getNext().invoke(request, response); // 继续下一个Valve
}
}
在 server.xml 中注册即可生效。
3.4 Servlet的加载与执行(Wrapper → Servlet实例)
-
Wrapper找到Servlet
Mapper 找到的目标是某个Wrapper,Wrapper 中保存了 Servlet 的配置信息。 -
Servlet加载
-
如果 Servlet 未被加载,
StandardWrapper会调用loadServlet()创建并初始化 Servlet 实例(调用init()方法)。
-
-
执行Servlet
-
最终由
StandardWrapperValve调用Servlet.service(),根据请求方法分发到doGet()、doPost()等方法。
-
-
返回响应
-
Servlet 处理完成后,将数据写入
HttpServletResponse,由 Connector 发送回客户端。
-
✅ 本章小结
-
Connector:接收 Socket 连接并解析协议。
-
CoyoteAdapter:适配成 Servlet API。
-
Mapper:根据 URL 定位到具体 Servlet。
-
Pipeline-Valve:处理链路,可扩展。
-
Wrapper:管理 Servlet 的生命周期并调用其方法。
第四章:性能优化与调优
4.1 I/O模型选择与性能对比
Tomcat 支持多种 I/O 模型,选择合适的模型是性能优化的第一步。
| I/O 模型 | 协议类名 | 特点 | 适用场景 |
|---|---|---|---|
| BIO(阻塞I/O) | Http11Protocol | 简单稳定,但每个请求一个线程,连接多时性能差 | 老系统、小并发 |
| NIO(非阻塞I/O) | Http11NioProtocol | 单线程管理多个连接,性能好,JDK自带 | 推荐默认 |
| NIO2(异步I/O) | Http11Nio2Protocol | JDK7+,AIO模型,适合高并发 | 高吞吐场景 |
| APR(本地库) | Http11AprProtocol | 使用Apache Portable Runtime,接近C语言性能 | 需要原生库,追求极限性能 |
切换示例(server.xml):
4.2 线程池配置调优策略
Tomcat 的 Connector 内部有线程池,决定了同时能处理多少请求。
-
核心参数:
-
maxThreads:最大工作线程数(默认200) -
minSpareThreads:启动时的最小空闲线程数(默认10) -
acceptCount:队列长度,满了会拒绝请求(默认100) -
connectionTimeout:连接超时时间(毫秒)
-
调优思路:
-
根据 CPU 核数和业务特性,计算合适的线程数(CPU 密集型:2×核数;I/O 密集型:更高)。
-
压测观察线程池是否饱和,必要时增加
acceptCount避免拒绝连接。 -
调短
connectionTimeout以减少无效连接占用。
配置示例:
4.3 内存泄漏问题与解决方案
Tomcat 在长时间运行中,可能因类加载器或未关闭的资源造成 PermGen/Metaspace 泄漏。
常见原因:
-
Web 应用热部署后,老的
ClassLoader未释放。 -
JDBC 连接、线程池、定时任务未关闭。
-
静态集合引用持有大对象。
解决策略:
-
禁用频繁热部署,生产中使用全量重启。
-
在
ServletContextListener.contextDestroyed()中手动关闭资源。 -
启用
org.apache.catalina.loader.WebappClassLoaderBase的内存泄漏检测日志:
4.4 高并发场景下的配置优化案例
假设业务是一个 高并发API服务,每天有数百万请求,可以做如下优化:
-
启用NIO模型,提升多连接处理能力。
-
加大线程池:
maxThreads="1000" minSpareThreads="100" acceptCount="500" -
压缩响应(减少网络传输量):
compression="on" compressionMinSize="1024" compressableMimeType="text/html,text/xml,text/plain,application/json" -
Keep-Alive优化:
maxKeepAliveRequests="100" keepAliveTimeout="5000" -
反向代理配合(Nginx + Tomcat):
-
Nginx 负责 SSL 终端和静态资源。
-
Tomcat 专注处理动态请求,减少负载。
-
第五章:实战案例与代码示例
5.1 自定义 Valve 实现请求日志记录
场景:我们希望记录每个 HTTP 请求的 URI 和处理耗时,这可以帮助排查性能问题。
代码实现
在 server.xml 中注册:
package com.example.tomcat;
import org.apache.catalina.Request;
import org.apache.catalina.Response;
import org.apache.catalina.Valve;
import org.apache.catalina.valves.ValveBase;
import javax.servlet.ServletException;
import java.io.IOException;
public class MyLogValve extends ValveBase {
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
long start = System.currentTimeMillis();
String uri = request.getRequestURI();
System.out.println("[MyLogValve] 请求URI: " + uri);
// 调用下一个Valve或最终的Servlet
getNext().invoke(request, response);
long duration = System.currentTimeMillis() - start;
System.out.println("[MyLogValve] 请求耗时: " + duration + "ms");
}
}
这样,所有到 localhost 的请求都会被我们的日志 Valve 拦截并记录。
5.2 server.xml 配置优化示例
假设我们要优化一个高并发 API 服务的 Tomcat:
优化要点:
-
NIO 模型:提升连接并发能力。
-
线程池加大:应对高并发。
-
响应压缩:减少网络带宽消耗。
-
Keep-Alive 优化:避免连接长时间占用。
5.3 Servlet 生命周期代码演示
场景:展示 Servlet 的 init()、service()、destroy() 调用时机。
示例代码:
package com.example.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LifeCycleServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("[Servlet] init() - 初始化Servlet");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("[Servlet] service() - 处理请求: " + req.getMethod());
resp.getWriter().write("Hello, this is LifeCycleServlet");
}
@Override
public void destroy() {
System.out.println("[Servlet] destroy() - 销毁Servlet");
}
}
web.xml 配置:
lifeCycleServlet
com.example.servlet.LifeCycleServlet
1
lifeCycleServlet
/lifecycle
运行结果:
-
第一次访问
/lifecycle时触发init()。 -
每次请求调用
service()。 -
Tomcat 关闭时调用
destroy()。

