跳转到内容

整体架构

Tomcat 启动时沿组件树向下传播,运行时沿 Connector、协议处理器和容器 Pipeline 流动。

先给答案:启动走组件树,请求走协议层与容器树

Section titled “先给答案:启动走组件树,请求走协议层与容器树”

Tomcat 启动时由 Catalina 构建 Server -> Service -> Connector + Engine 组件树,再通过 Lifecycle 向下初始化和启动;请求到来后,Connector/Coyote 负责 socket 与 HTTP,Mapper 选择 Host、Context、Wrapper,Valve 链最终调用 Servlet。

两条主线的边界必须分开:线程池和协议解析属于连接器,应用路由与 Servlet 生命周期属于容器,Web 应用类加载器还要在停止时清理线程、ThreadLocal 和驱动。混淆这些所有权会造成调优方向错误或重部署泄漏。

Bootstrap/Catalina -> Server -> Service -> Connector + Engine
Engine -> Host -> Context -> Wrapper -> Servlet
socket -> NioEndpoint -> Http11Processor -> CoyoteAdapter -> Mapper
-> EngineValve -> HostValve -> ContextValve -> WrapperValve -> Servlet

Catalina#start 位于 java/org/apache/catalina/startup/Catalina.java:868;LifecycleBase#init 与 start 位于 java/org/apache/catalina/util/LifecycleBase.java:121、:145。Service 启动在 StandardService.java:424,Connector 初始化/启动在 Connector.java:1255、:1300。

NioEndpoint#processKey 位于 java/org/apache/tomcat/util/net/NioEndpoint.java:1129,Http11Processor#service 位于 java/org/apache/coyote/http11/Http11Processor.java:254,CoyoteAdapter#service 位于 java/org/apache/catalina/connector/CoyoteAdapter.java:305,Mapper#map 位于 java/org/apache/catalina/mapper/Mapper.java:688。之后由 StandardEngineValve.java:54 开始逐级进入容器。

替代方案:把协议解析、路由和 Servlet 调用放进一个请求处理器。 为什么不行:协议演进、虚拟主机、Web 应用生命周期和类加载隔离会互相污染。Tomcat 用 Coyote/Catalina Adapter、Mapper 和 Valve 分开承担边界。

风险 触发条件 诊断入口
启动失败 生命周期子组件异常 LifecycleBase 状态与根因日志
请求排队 Endpoint 或 Servlet 阻塞 线程池、队列、慢请求
路由错误 Host/Context/Wrapper 不匹配 Mapper 与部署命名
热部署泄漏 Webapp 类仍被外部引用 WebappClassLoaderBase 停止清理

面试锚点

  • 画出 Tomcat 从 socket 到 Servlet 的调用链。
  • Connector 与 Container 为什么分离?
  • Mapper 和 Valve 的职责是什么?