Skip to content

面试专题

This content is not available in your language yet.

Tomcat 面试要能说明连接器、协议层、容器树和应用类加载器之间的边界。

先给答案:先区分连接器、容器与应用生命周期

Section titled “先给答案:先区分连接器、容器与应用生命周期”

Tomcat 用 Connector/Coyote 接收并解析网络请求,用 Mapper 和容器 Pipeline 把请求送到目标 Servlet;组件启动则由统一 Lifecycle 沿 Server、Service、Engine 等层级传播。一次请求慢,要先判断耗时发生在接入、协议、Valve 还是应用代码。

类加载和关闭问题属于另一条所有权链:每个 Web 应用需要依赖隔离,停止时还必须清理应用创建的线程、ThreadLocal、JDBC 驱动等引用。连接数、工作线程数和应用并发不是同一个概念,调参前必须确认真正饱和的层。

Server → Service → Connector + Engine → Host → Context → Wrapper。配置构建在 Catalina.java:538,Connector 生命周期在 Connector.java:1255、:1300,容器调用由 StandardEngineValve.java:54 开始。

NioEndpoint 发现 socket 事件,Http11Processor#service(Http11Processor.java:254)解析并在 :401 交给 Adapter;CoyoteAdapter#service(CoyoteAdapter.java:305)在 :347 进入 Pipeline;Mapper.java:688 完成路由,最后 Wrapper Valve 调用 Servlet。

WebappClassLoaderBase#loadClass(WebappClassLoaderBase.java:1132)按委派配置处理顺序,隔离应用依赖;停止流程从 :1387 开始,负责清理线程、ThreadLocal 和 JDBC 驱动。

Connector 和 Container 为什么分离?

Section titled “Connector 和 Container 为什么分离?”

Connector 面向网络协议,Container 面向 Servlet 路由和应用生命周期。CoyoteAdapter 是两者的防腐层,让 HTTP/1.1、HTTP/2 等协议复用 Catalina 容器。

为什么异步 Servlet 仍可能耗尽线程?

Section titled “为什么异步 Servlet 仍可能耗尽线程?”

异步只释放原始请求线程,不会消除业务线程、连接数、输出缓冲和下游压力。必须限制异步任务并正确结束 AsyncContext。

QPS 上升但 CPU 不高、请求大量超时,先查什么?

Section titled “QPS 上升但 CPU 不高、请求大量超时,先查什么?”

区分 Selector、协议 Worker、Servlet 线程池和下游连接池。若 Worker 饥饿,查阻塞 Servlet、锁等待和异步队列;若 Selector 空转,查 SelectionKey 和异常连接关闭。

热部署后 Metaspace 增长如何定位?

Section titled “热部署后 Metaspace 增长如何定位?”

统计旧 WebappClassLoader,检查线程、Timer、ThreadLocal、静态缓存、JDBC Driver 和日志框架引用。不要只调大 Metaspace。

面试锚点

  • 说清 Coyote、Catalina、Connector、Container 的边界。
  • 画出 socket 到 Servlet 的调用链。
  • 解释 Mapper 查找与 Valve 执行为什么分离。