前阵子,一个粉丝在评论区问我:“小米,我最近在准备 Java 社招面试,面试官老喜欢问 Tomcat 的底层问题。上次他问我 ‘Tomcat 的 Container 是怎么处理请求的?’,我一时语塞,差点当场原地超度……”
哈哈哈,我懂那种感觉。
面试官微笑着看你,你的脑子一片空白,只剩一句话在循环播放——“我是谁,我在哪,我在干什么?”
所以今天,小米就来带你轻轻松松地搞懂:
Tomcat 的 Container 是怎么一步步处理请求的。
放心,我不讲死板的概念,我给你讲个故事,让你看懂、记住、还能讲出来。
Tomcat 的“家族体系”:一个层层递进的组织架构
想象一下,Tomcat 就像一个大型的公司。这个公司有四个层级的“部门”,它们分别叫:
- Engine(引擎总管)
- Host(主机经理)
- Context(项目主管)
- Wrapper(Servlet 包装员)
这些家伙统称为 Container(容器家族) 。听起来抽象?没关系,我们先来形象地感受一下它们的关系。
故事这样开始:
一天,一个 HTTP 请求——我们叫他“小请求”——敲响了 Tomcat 公司的大门。
“你好,我是一条请求,请问谁能帮我找到 http://localhost:8080/demo/hello ?”
门卫 Connector 接过话,说:“好的,你找的这家公司叫 Tomcat,我负责接客,你的请求我收到了。来,我送你去我们公司的内部处理中心——Container 部门。”
于是,“小请求”被交到了 Container 家族的门口。
接下来,就是一场层层转交的冒险。
Container 家族的分工:谁负责哪一摊?
小请求一路往里走,先见到了最上层的主管——Engine 容器。
1. Engine:大总管
Engine 是整个容器链的老大。它不干活,但负责分派任务。
他看着请求说:“你这个请求是访问哪个虚拟主机的?哦,是 localhost,那我派你去找我们的 Host 部门经理。”
于是,小请求被派去了 Host 容器。
2. Host:虚拟主机经理
Host 容器就像一台服务器上的“项目宿主”。
比如你在 Tomcat 的 conf/server.xml 里配置多个 ,就是有多个虚拟主机。
Host 问:“你是访问 /demo 这个项目吗?那你得去找我们的 Context 主管。”
3. Context:项目主管
Context 对应着一个 Web 应用,比如 /demo。
它就像一个项目经理,负责整个 Web 应用的生命周期、Servlet 注册、过滤器、监听器,统统管着。
Context 一看:“原来你是找 /hello 这个接口,那这个接口归我们 HelloServlet 处理,我让 Wrapper 去找它。”
Wrapper:Servlet 包装员
Wrapper 是最基层的容器,它直接包裹着一个个 Servlet。比如 HelloServlet、LoginServlet 等。
Wrapper 负责:
- 加载 Servlet 实例(第一次请求时)
- 调用 Servlet 的 service() 方法 来处理请求。
到这一步,小请求终于见到了它真正的“服务员”——HelloServlet。
Servlet 处理完请求后,返回一个 Response,小请求带着响应结果,顺着原路返回,回到 Connector,最后返回给浏览器。
整个流程,就像一场严密的公司运作。
层层传递的秘密:Pipeline 与 Valve
看到这里,你可能觉得这只是“分发层级”,但 Tomcat 可没那么简单。真正让它灵活强大的,是 Pipeline(管道) 和 Valve(阀门) 机制。
想象一下:
每个容器不仅能“接力”,还能“拦截、加工、记录”。这就像每个部门门口都装了一套“流水线”系统。
请求经过时,可能会:
- 被 Valve 拦截做日志(类似 Filter);
- 被修改 Header;
- 被检测权限;
- 最后才交给下一级。
而这套机制,就是 Tomcat 的拦截器体系。
每个容器(Engine、Host、Context、Wrapper)都有自己的 Pipeline,每个 Pipeline 里可以装多个 Valve。
请求从上往下传递时,会经过:
Engine → Host → Context → Wrapper
每一层都可以插自己的 Valve。
最后,到达 Wrapper 的 StandardWrapperValve 时,就会真正调用 Servlet.service() 方法。
这时候,小请求终于被执行完毕,响应数据被包装成 Response,再经过同样的 Valve 反向流出,一层层返回出去。
是不是有点像 SpringMVC 的 HandlerInterceptor + Filter 的合体版?
没错,这正是 Tomcat 的高灵活性所在。
用一口气总结整个流程
好,我们用一口气,把整个请求流程串起来。
- Connector 接收请求: 解析 HTTP 请求,封装成 Request 和 Response 对象。
- 传给 Engine 容器: Engine 根据虚拟主机名,找到对应的 Host。
- Host 容器分发: Host 根据 URI 路径,找到对应的 Context(即某个 Web 应用)。
- Context 查找 Servlet: Context 再根据 /hello 映射,找到对应的 Wrapper。
- Wrapper 调用 Servlet: Wrapper 调用 Servlet 的 service() 方法执行业务逻辑。
- 返回 Response: Response 沿着 Pipeline 反向返回,Connector 把结果写回浏览器。
整个过程用一句话总结就是:
Connector 收请求,Container 传下去,Servlet 干活,Valve 拦截,Response 回来。
这,就是 Tomcat 的核心“协作链”。
面试官会怎么问?
讲完原理,我们再来看看——面试官喜欢“挖坑”的地方。
问1:Container 有几种类型?各自作用?
答:
- Engine:整个 Catalina 容器的顶层入口;
- Host:代表一个虚拟主机;
- Context:代表一个 Web 应用;
- Wrapper:包装一个具体 Servlet。
问2:Tomcat 怎么找到目标 Servlet?
答:
- Connector 收请求;
- Engine 按域名匹配 Host;
- Host 按路径匹配 Context;
- Context 按映射匹配 Servlet(Wrapper)。
问3:Pipeline 和 Valve 是干嘛的?
答:
Pipeline 是管道模型,Valve 是具体的阀门实现,每个 Container 都有自己的 Pipeline,请求经过每一层 Pipeline 的 Valve,最终到达 Servlet。
问4:Wrapper 的 StandardWrapperValve 有什么作用?
答:
它是 Tomcat 调用 Servlet 的最终入口,会先初始化 Servlet 实例,再执行 service()。
面试时,如果你能讲出这些,还能带一点故事式的比喻,面试官基本就会露出那种“懂啊,这孩子懂行”的笑容。
用一个比喻,让你彻底记住
我最喜欢的比喻是:Tomcat 就像一个大型餐厅。
- Connector:迎宾员,接待客人(请求)
- Engine:总经理,决定送去哪个厨房(Host)
- Host:厨房主管,一个厨房可以做多个菜系(多个项目)
- Context:厨师长,负责一个具体菜系(Web 应用)
- Wrapper:厨师本人(Servlet)
- Valve:检查员、调味员,在菜品上桌前负责加料、质检、记录日志
当一道菜(请求)被送进来,从迎宾、分配、下单、烹饪到上菜,每个环节都协同工作。最终,顾客(浏览器)吃到的,就是 Servlet 输出的结果。
是不是一下就通了?
写在最后:理解架构,才能玩得更深
很多人学 Tomcat 只是停留在“启动一下服务器”、“看下日志”层面,但当你真正理解了它的容器架构,你会发现:
Tomcat 不只是“跑个 Servlet”那么简单。它是一套高度模块化的“请求处理流水线”,每一层都可以扩展、定制、拦截。
比如:
- 想加监控?写个 Valve。
- 想加权限?写个 Context 拦截器。
- 想做负载?修改 Host 层逻辑。
理解了 Container,你就真正掌握了 Tomcat 的灵魂。
END
总结一句话送给你:
“懂 Connector,你会启动服务器;懂 Container,你能掌控服务器。”
下次再遇到面试官问“Tomcat 的 Container 是怎么处理请求的?”,你只要淡定地一笑,然后讲出“小请求进公司”的故事,他大概率会在心里默默打个 ——
“这个人,不光会背,还真懂。”
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!