必须同时配置server.shutdown=graceful和spring.lifecycle.timeout-per-shutdown-phase,否则优雅停机不生效;前者启用Web容器拒绝新请求并等待旧请求完成,后者设定最大等待时间(如90s),缺一不可。

Spring Boot 2.3+ 默认支持优雅停机,但必须显式启用并配对超时参数,否则 server.shutdown=graceful 不生效,应用仍会立即终止线程。
Spring Boot 2.3 及以上版本:必须配齐两个配置项
只写 server.shutdown=graceful 是不够的。Spring Boot 会进入优雅停机流程,但若没设生命周期超时,它会在默认 30 秒(某些版本是 0)后强制中断,导致请求被截断。
-
server.shutdown=graceful:启用优雅停机开关,让 Web 容器停止接收新连接 -
spring.lifecycle.timeout-per-shutdown-phase=60s:指定整个关机阶段最大等待时间,建议设为略大于你最长请求耗时(如 60–120 秒)
这两个配置必须同时存在,缺一不可。application.yml 示例:
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 90s
Spring Boot 2.2 及更早版本:靠 Actuator 的 /actuator/shutdown 不够可靠
该端点只是触发 JVM 关闭钩子,并不控制 Web 容器行为。Tomcat/Jetty 会立刻关闭连接队列,正在读取请求体或写响应的线程可能被中断,造成客户端收到不完整响应或 Connection reset。
- 仅开启
management.endpoint.shutdown.enabled=true和暴露/actuator/shutdown无法保证请求完成 - 需额外监听
ContextClosedEvent或注册SmartLifecycle,在事件中主动等待业务线程池清空 - 更稳妥的做法是弃用该端点,改用操作系统信号(
SIGTERM)+ 容器层配合(如 Docker 的stop_grace_period)
Docker 环境下必须同步配置容器 stop 超时
Docker 默认只给容器 10 秒处理 SIGTERM,超时后直接发 SIGKILL。即使 Spring Boot 设置了 90 秒等待,Docker 也会在第 11 秒强行杀掉进程。
- 在
docker run中加--stop-timeout=120 - 在
docker-compose.yml中配stop_grace_period: 120s - Kubernetes 则需设置
terminationGracePeriodSeconds: 120
这个值必须 ≥ Spring Boot 的 spring.lifecycle.timeout-per-shutdown-phase,否则容器层先动手,JVM 层没机会执行完。
自定义线程池未参与优雅停机是个隐形陷阱
Spring Boot 的优雅停机只管理内嵌 Web 容器(Tomcat/Jetty/Undertow)和 Spring 生命周期 Bean,但不会自动等待你手动创建的 ThreadPoolExecutor 或 Executors.newFixedThreadPool()。
- 如果你用
@Async或自己 submit 任务到线程池,这些任务可能在关机时被丢弃 - 解决方法:把线程池声明为
@Bean并实现SmartLifecycle,在stop()方法中调用shutdown()+awaitTermination() - 或者改用 Spring 管理的
TaskExecutor,它会自动纳入生命周期管理
最容易被忽略的是:关机逻辑依赖于线程池是否“可被中断”。如果任务里有 Thread.sleep() 或阻塞 I/O,且没响应中断,awaitTermination() 就会卡住,拖垮整个停机流程。


















