Tomcat 的核心架构是什么?一个 HTTP 请求如何到达 Servlet?
简化版
Tomcat 由两大部分组成:Connector(连接器) 负责网络通信——监听端口、接收 TCP 连接、解析 HTTP 协议、封装成 Request/Response 对象;Container(容器,即 Catalina) 负责应用处理——按 Engine → Host → Context → Wrapper 四级容器层层定位到目标 Servlet 并调用它。请求从端口进入 Connector,解析后经 Adapter 交给 Container,Mapper 根据域名、路径、Servlet 映射找到对应的 Wrapper,执行 Filter 链后调用 Servlet 的 service() 方法。
详细版
整体架构(一个 Server 包含多个 Service):
Server(整个 Tomcat 实例)
└─ Service(连接器 + 容器的组合,可有多个)
├─ Connector(Coyote):网络 + 协议 ← 可多个(HTTP、AJP)
└─ Engine(Catalina 容器顶层)
└─ Host(虚拟主机,对应一个域名,如 www.a.com)
└─ Context(一个 Web 应用,对应一个 war/目录)
└─ Wrapper(封装一个具体的 Servlet)
两大核心组件分工:
| 组件 | 名字 | 职责 |
|---|---|---|
| Connector | Coyote | 监听端口、接收连接、解析 HTTP、封装 Request/Response、支持 BIO/NIO/APR |
| Container | Catalina | 管理 Web 应用与 Servlet 生命周期,按四级容器定位并调用 Servlet |
一个请求的完整流程:
- Connector 监听端口,接收 TCP 连接。
- 按 I/O 模型(现代默认 NIO)读取字节流,解析 HTTP 请求行、请求头、body。
- 封装成 Tomcat 的
Request/Response,通过 Adapter(CoyoteAdapter) 交给 Container。 - Mapper 根据
Host头找 Host、context path找 Context、servlet mapping找 Wrapper。 - 请求依次流经 Engine → Host → Context → Wrapper 各级的 Pipeline(管道)+ Valve(阀门)。
- 到 Wrapper 后执行 Filter 链,最后调用目标 Servlet 的
service()(Spring 应用里就是DispatcherServlet)。
完整版教学
一、为什么要分 Connector 和 Container
Tomcat 本质是一个 Servlet 容器 + HTTP 服务器。它要干两件性质完全不同的事:
- 对外:处理网络——怎么接收 TCP 字节、怎么解析 HTTP 协议、怎么把响应写回网络。这是协议和 I/O 层面的事,和「是哪个 Web 应用」无关。
- 对内:处理应用——这个请求属于哪个域名、哪个 Web 应用、该调用哪个 Servlet,Servlet 怎么初始化销毁。这是应用容器层面的事,和「用什么协议进来」无关。
Tomcat 把这两件事拆成 Connector(管网络与协议) 和 Container(管应用与 Servlet),用 Adapter 把两者解耦连接起来。好处是协议可以换、容器不变——支持 HTTP、AJP 等多种 Connector,共用同一套 Container。理解这个「网络层 / 应用层分离」是理解 Tomcat 架构的入口。
| 部分 | 面向的问题 | 典型对象 | 变化时影响 |
|---|---|---|---|
| Connector | 网络连接、协议解析、I/O 模型 | Endpoint、Processor、Adapter | 换 HTTP/AJP 或 BIO/NIO,不应改变 Servlet 管理方式 |
| Container | 应用定位、生命周期、调用链 | Engine、Host、Context、Wrapper | 部署应用、映射 Servlet,不应关心 TCP 字节怎么读 |
记忆钩子:Connector 负责把“线上的字节”翻译成请求对象,Container 负责把“请求对象”送到正确的 Web 应用和 Servlet。
二、Connector(Coyote):把字节变成请求对象
Connector 又叫 Coyote,它内部关键分工:
- Endpoint:负责底层 Socket 通信——监听端口、接收连接、管理 I/O 线程。这里决定了 I/O 模型:
- BIO(老,一连接一线程,已淘汰);
- NIO(现代默认,基于多路复用,少量线程扛大量连接);
- NIO.2 / APR(进一步优化)。
- Processor:负责协议解析——把 Endpoint 收到的字节流解析成 HTTP 请求(请求行、请求头、body),并把响应按 HTTP 格式写回。
- Adapter(CoyoteAdapter):适配器,把 Coyote 自己的
Request/Response转成标准的 Servlet API 的HttpServletRequest/HttpServletResponse,交给 Container。
一句话:Connector 把「网络字节」变成「Servlet 能用的 Request 对象」。
三、Container 的四级容器:Engine → Host → Context → Wrapper
Container(Catalina)是一个四级嵌套的结构,每一级对应一个概念:
- Engine(引擎):容器顶层,代表整个 Catalina 引擎,一个 Service 只有一个 Engine。
- Host(虚拟主机):对应一个域名(如
www.example.com)。一个 Tomcat 可以配多个 Host,实现虚拟主机(不同域名指向不同应用)。 - Context(上下文):对应一个 Web 应用(一个 war 包或一个目录),有自己的
context path(如/app)、独立的类加载器、独立的 Servlet 集合。 - Wrapper(包装器):最底层,封装一个具体的 Servlet——管理这个 Servlet 的加载、初始化、
service()调用、销毁。
这四级是父子包含关系:一个 Engine 有多个 Host,一个 Host 有多个 Context,一个 Context 有多个 Wrapper。请求定位 Servlet 的过程,就是沿这条层级从上往下找的过程。
四、Mapper:请求如何精确定位到 Servlet
请求进入 Container 后,靠 Mapper(映射器) 一步步定位到目标 Wrapper:
- 定位 Host:看 HTTP 请求头里的
Host(域名),匹配到对应的 Host 容器。 - 定位 Context:看请求 URL 的 context path(如
/app/user/list里的/app),匹配到对应的 Web 应用(Context)。 - 定位 Wrapper:在 Context 内,看 servlet mapping(
web.xml或注解里配的 URL 映射,如/user/*),匹配到对应的 Servlet(Wrapper)。
举例 http://www.a.com/app/user/list:Host = www.a.com,Context = /app,剩下 /user/list 按 servlet mapping 找到处理它的 Servlet。这就是「域名 → 应用 → Servlet」的三层映射。
GET /app/user/list HTTP/1.1
Host: www.a.com
Connector 解析 HTTP
-> Mapper 找 Host: www.a.com
-> Mapper 找 Context: /app
-> Mapper 找 Wrapper: /user/*
-> Filter 链
-> Servlet.service()
如果同一台 Tomcat 同时部署 2 个 Host、每个 Host 下 3 个 Context,每个 Context 有 20 个 Servlet,Mapper 的价值就在于把一次请求从这些候选项里快速缩小到 1 个 Wrapper,而不是让业务层自己猜。
五、Pipeline 与 Valve:容器的责任链扩展点
Container 的每一级(Engine/Host/Context/Wrapper)都有一个 Pipeline(管道),管道上串着若干 Valve(阀门)。请求流经某一级容器时,会依次经过该级 Pipeline 上的所有 Valve,最后由管道末端的 BasicValve 把请求传给下一级容器。
这本质是一个责任链模式——Valve 是 Tomcat 内部的横切扩展点,可以在请求流经各级容器时插入逻辑,例如:
- AccessLogValve:记录访问日志(在 Host 级)。
- ErrorReportValve:错误页面处理。
- 认证、限流 等自定义 Valve。
Valve 和 Filter 的区别:Valve 是 Tomcat 容器级别的(对所有应用生效、是 Tomcat 私有机制),Filter 是 Servlet 规范级别的(在具体 Web 应用内、跨容器可移植)。请求是先过 Valve(容器级),到 Wrapper 后再过 Filter(应用级),最后才到 Servlet。
六、和 Spring MVC 的关系(易混点)
一个高频易混点:Spring MVC 的 DispatcherServlet 对 Tomcat 而言,就是一个普通的 Servlet。
- Tomcat 负责把请求送到
DispatcherServlet(它是 Context 里的一个 Wrapper)——这是 Tomcat 的 servlet mapping 层面的映射(通常DispatcherServlet映射/)。 - 进了
DispatcherServlet之后,Spring MVC 内部再用 HandlerMapping 找到具体的@Controller方法——这是 Spring 层面的映射。
两层映射不要混:Tomcat 只管「请求 → 哪个 Servlet」,Spring MVC 管「进了 DispatcherServlet 后 → 哪个 Controller」。理解这一点,排查「请求到不了 Controller」时才能分清是 Tomcat 层没进来、还是 Spring 层没匹配到。
七、排查「请求到不了目标」的分层思路
当请求没到达预期的 Controller/Servlet 时,按架构分层从外往里排查效率最高:
- 端口 / Connector:请求有没有进到 Tomcat?看端口是否正确、Connector 是否正常、防火墙。
- Host / Context:域名和应用路径对不对?context path 配错会 404。
- Servlet mapping / Filter:URL 映射对不对?有没有 Filter 提前拦截返回了?
- Spring 层:进了 DispatcherServlet 后,HandlerMapping 有没有匹配到 Controller?
分层排查比一上来就怀疑业务代码快得多——这正是理解 Tomcat 架构的实战价值。
八、常见误区与追问
- 误区:Tomcat 只是简单调用 Servlet。 调用 Servlet 之前还有 Connector 解析、Adapter 适配、Mapper 定位、Pipeline/Valve、Filter 链等多层处理。
- 误区:Host、Context、Wrapper 都是同一个概念。 Host 对应域名,Context 对应 Web 应用,Wrapper 才封装具体 Servlet,层级不同。
- 追问:Connector 和 Container 为什么要解耦? 这样网络协议和应用容器可以独立演进,一个 Container 可以被不同 Connector 使用。
- 追问:Valve 和 Filter 最大区别是什么? Valve 是 Tomcat 私有的容器级扩展点,Filter 是 Servlet 规范的应用级扩展点,Filter 更可移植。
- 误区:Spring MVC 的 Controller 是 Tomcat 直接找到的。 Tomcat 只找到 DispatcherServlet,Controller 方法由 Spring MVC 的 HandlerMapping 再匹配。
- 追问:请求 404 应该按什么顺序排查? 先看端口和 Connector,再看 Host/Context,再看 servlet mapping/Filter,最后看 Spring HandlerMapping。
九、加强记忆
Tomcat = Connector(Coyote,管网络+协议)+ Container(Catalina,管应用+Servlet),用 Adapter 解耦。Connector 三件套:Endpoint(Socket,决定 BIO/NIO/APR)、Processor(解析 HTTP)、Adapter(转成 Servlet API)。Container 四级:Engine(引擎)→ Host(域名)→ Context(Web 应用)→ Wrapper(Servlet),靠 Mapper 按「域名→应用→servlet mapping」三层定位。每级容器有 Pipeline + Valve(容器级责任链扩展点,区别于应用级的 Filter)。请求路径:端口 → Connector 解析 → Adapter → Mapper 定位 Wrapper → Valve → Filter → Servlet.service()。Spring MVC 的 DispatcherServlet 只是一个 Servlet,Tomcat 映射和 Spring HandlerMapping 是两层别混。