spring boot优雅停机需分阶段执行:先拒新请求、再等待旧请求完成、最后释放资源;需配置server.shutdown=graceful和spring.lifecycle.timeout-per-shutdown-phase,配合@predestroy、smartlifecycle及k8s prestop钩子实现全流程可控。

Spring Boot 优雅停机不是“加个配置就完事”,而是需要明确阶段、匹配环境、覆盖关键资源释放点。核心在于:让应用在收到停止信号后,先拒新、再等旧、最后清资源,全程可控可观察。
基础配置:启用并设好等待窗口
Spring Boot 2.3+ 版本已内置支持,只需两行配置:
-
启用优雅停机:设置
server.shutdown=graceful -
设定最大宽限期:设置
spring.lifecycle.timeout-per-shutdown-phase=45s(建议根据业务最长请求耗时上浮 10–20 秒,避免误杀)
YAML 格式示例:
server:shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 45s
注意:该配置对 Tomcat、Jetty、Undertow 和 Reactor Netty 均生效;若用的是 Spring Boot 2.2 或更早版本,则需手动注册 GracefulShutdown Bean 并定制 WebServerFactory。
资源释放:靠 @PreDestroy + SmartLifecycle + Shutdown Hook 三层兜底
仅靠容器层等待不够,数据库连接池、消息消费者、定时任务、自定义线程池等必须主动释放:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- @PreDestroy 方法:标注在组件类上,用于关闭单例 Bean 内部资源(如关闭 Netty Channel、断开 Redis 连接)
-
实现 SmartLifecycle 接口:适合需控制启动/停止顺序的组件(如 MQ 消费者应早于业务服务停止),重写
stop()并传入Runnable回调确保异步清理完成后再通知上下文 - JVM Shutdown Hook(慎用):仅作最后保险,比如强制 flush 日志缓冲区或上报终止指标;不建议在此做阻塞操作,因它无超时保障,可能拖垮整个停机流程
K8s 环境适配:preStop 钩子 + terminationGracePeriodSeconds 对齐
在 Kubernetes 中,直接 kill 容器进程会跳过 Spring 的优雅逻辑。必须通过 preStop 主动触发:
- 确保 Actuator 端点已启用:
management.endpoints.web.exposure.include=health,info,graceful-shutdown - Deployment 中配置
preStop执行 HTTP 请求(推荐):
preStop:
exec:
command: ["sh", "-c", "curl -X POST http://localhost:8080/actuator/graceful-shutdown?timeout=45"]
terminationGracePeriodSeconds: 60
注意:terminationGracePeriodSeconds 必须 ≥ 优雅停机超时时间 + 网络延迟余量,否则 K8s 会在 Spring 完成前发 SIGKILL 强制终止。
验证与可观测性:别只看日志,要抓关键信号
停机是否真正“优雅”,不能只等应用退出。需确认以下三点:
- 收到
SIGTERM后,Web 容器是否立即停止 Accept 新连接(可用netstat -an | grep :8080观察 ESTABLISHED 数不再增长) - Actuator 的
/actuator/health在停机开始后快速变为OUT_OF_SERVICE,告知注册中心或 LB 下线 - 日志中出现
Commencing graceful shutdown→Waiting for active requests to complete→ContextClosedEvent published完整链路
建议在停机流程末尾添加一条带时间戳的 INFO 日志,例如 "Graceful shutdown completed at ${LocalDateTime.now()}",便于定位卡点。










