bigywater.tech
Spring · 17

SmartLifecycle:启动与停止的阶段(phase)

SmartLifecycle 的 phase 到底怎么排?refresh 时哪些会自动启动?关闭时每个阶段怎么等?一个停不下来的 Bean 会怎样?这篇在 Spring Framework 7.0.9 上用带时间戳的事件逐项验证。

308 对 918 ms
三个 phase 相同与三个 phase 不同的 Bean 各异步停 300 ms 时,close() 的耗时
从小到大
启动的 phase 顺序;停止是从大到小
1004 ms
一个 Bean 不回 callback、timeoutPerShutdownPhase 设成 1000 ms 时 close() 的耗时

阶段顺序

实测 · 本机执行输出
  --- refresh 完成后(5 个 SmartLifecycle,phase 各不同,@Bean 的定义顺序是 p100、pMin、p0、pMax、p-100)
  1.   321 ms  pMin.start()  (phase -2147483648)
  2.   323 ms  p-100.start()  (phase -100)
  3.   323 ms  p0(默认 phase).start()  (phase 0)
  4.   323 ms  p100.start()  (phase 100)
  5.   323 ms  pMax.start()  (phase 2147483647)
  --- close() 之后
  1.   326 ms  pMax.stop()  耗时 0 ms
  2.   326 ms  p100.stop()  耗时 0 ms
  3.   326 ms  p0(默认 phase).stop()  耗时 0 ms
  4.   327 ms  p-100.stop()  耗时 0 ms
  5.   327 ms  pMin.stop()  耗时 0 ms
  6.   327 ms  Destroy.@PreDestroy

启动 phase 升序,停止 phase 降序;停止先于单例的销毁回调。

自动启动

实测 · 本机执行输出
  --- refresh 完成后
  1.   358 ms  auto.start()  (phase 0)
  --- context.start() 之后
  1.   361 ms  --- 调用 context.start()
  2.   361 ms  manual(isAutoStartup=false).start()  (phase 0)
  3.   361 ms  Plain(普通 Lifecycle).start()
  --- 手动 start manual 之后
  1.   361 ms  --- 调用 manual 的 start()
  2.   361 ms  manual(isAutoStartup=false).start()  (phase 0)

refresh 只启动 isAutoStartup 为 true 的 SmartLifecycle;context.start() 启动所有 Lifecycle。

分阶段停止

实测 · 本机执行输出
  --- 同一个 phase(都是 10)的三个 Bean,各异步停 300 ms(close 耗时 308 ms)
  1.   301 ms  a.stop(callback) 开始,异步300 ms 后回调
  2.   302 ms  b.stop(callback) 开始,异步300 ms 后回调
  3.   302 ms  c.stop(callback) 开始,异步300 ms 后回调
  4.   603 ms  b 异步停止完成,调用 callback
  5.   607 ms  a 异步停止完成,调用 callback
  6.   607 ms  c 异步停止完成,调用 callback
  7.   608 ms  close() 返回
  --- 三个不同 phase(10、20、30)各异步停 300 ms(close 耗时 918 ms)
  1.   304 ms  c.stop(callback) 开始,异步300 ms 后回调
  2.   609 ms  c 异步停止完成,调用 callback
  3.   609 ms  b.stop(callback) 开始,异步300 ms 后回调
  4.   914 ms  b 异步停止完成,调用 callback
  5.   915 ms  a.stop(callback) 开始,异步300 ms 后回调
  6.  1220 ms  a 异步停止完成,调用 callback
  7.  1221 ms  close() 返回

同一 phase 的并行停,不同 phase 的串行停,总耗时分别约等于最慢的一个和全部相加。

停不下来

实测 · 本机执行输出
  --- Hang 不调用 callback,timeoutPerShutdownPhase = 1000 ms(close 耗时 1004 ms)
  1.   325 ms  Hang.stop(callback):永远不调用 callback
  2.  1328 ms  other(phase 0).stop()  耗时 0 ms
  3.  1329 ms  close() 返回

stop(callback) 不回调时整个关闭会等到 timeoutPerShutdownPhase。

分步演示

SmartLifecycle 与 phase
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。用不带 Boot 的 Spring Framework 7.0.9;时间是相对 JVM 里的静态初始化时刻的毫秒数,每次运行会有几 ms 的抖动(例如第三节 close 耗时 308 ms,另一次运行里是 300 多 ms);默认的 timeoutPerShutdownPhase(30 秒)是文档里的值,这篇只测了设成 1000 ms 的情形
    • 没有验证:Boot 的 spring.lifecycle.timeout-per-shutdown-phase 配置项和 Tomcat 的 WebServerStartStopLifecycle(见后面的 Boot 篇);同一 phase 里多个 Bean 同步 stop() 的顺序;SmartLifecycle 抛异常时的行为;Spring Framework 6.1 之后与 CRaC 的检查点恢复的交互;Lifecycle 与 @PreDestroy 的组合使用建议
    京ICP备2026067502号-1京公网安备11010502063487号