生命周期与启动
This content is not available in your language yet.
Tomcat 启动由配置解析、组件树构建、生命周期状态机和父子级联启动共同完成。
先给答案:Tomcat 生命周期状态机解决的是“复杂组件树如何一致启动和停止”
Section titled “先给答案:Tomcat 生命周期状态机解决的是“复杂组件树如何一致启动和停止””Tomcat 不是一个对象,而是一棵组件树。每个组件都需要经历初始化、启动、运行、停止和销毁,父子组件的顺序必须一致;状态机把非法跃迁拒绝在组件内部,监听器则把生命周期事件传播给依赖方。
如果只靠调用约定,重复 start、半途失败和父组件停止时的子组件清理都会变成隐性 bug。状态机的代价是启动逻辑更分散,但它把“当前组件处于什么状态、下一步能做什么”变成了可检查事实。
Bootstrap -> Catalina.load -> Digester -> Server/Service/Connector/Engine -> init() -> start()Catalina#start 在 java/org/apache/catalina/startup/Catalina.java:868;Connector 规则在 Catalina.java:538。LifecycleBase#init 在 java/org/apache/catalina/util/LifecycleBase.java:121 调用 initInternal(:128、:141);start 在 :145 调用 startInternal(:170、:199)。
为什么采用状态机
Section titled “为什么采用状态机”替代方案:每个组件使用独立的 init/start 布尔值。
为什么不行:无法表达初始化中、启动准备和失败回滚等中间状态,也无法统一处理重复调用。LifecycleState 让父子组件有明确的状态传播边界。
| 场景 | 现象 | 原因 | 规避 |
|---|---|---|---|
| 重复启动 | 返回或报状态错误 | 已处于 STARTED |
只使用公共生命周期 API |
| 子组件失败 | 整体启动失败 | 服务树不完整 | 查最内层异常 |
| 只启动 Connector | 端口开但请求失败 | 没有 Container/Adapter | 通过 Service 编排 |
| 停止超时 | 线程仍存活 | Endpoint 或应用线程未退出 | 检查 Executor 和异步任务 |
生命周期状态机适合连接池、消息消费者和插件系统:把调用顺序约束集中到基类,并让失败状态可观测。
面试锚点
init与start为什么拆开?- 父子容器如何保证启动顺序?
- 启动失败如何回滚资源?