本文目录导读:

- 核心机制:
Runtime.getRuntime().addShutdownHook() - Spring Boot 原生支持(最常用)
- Spring Cloud / 微服务场景
- Web 容器级别支持
- 使用信号处理(Linux/Unix)
- 框架支持总结表
- 生产环境最佳实践
Java 对优雅停机(Graceful Shutdown)有 原生支持,且在不同版本中不断增强,主要通过在关闭时等待正在执行的任务完成、释放资源来实现,而非强制 kill -9。
以下是 Java 实现优雅停机的几种方式及版本支持情况:
核心机制:Runtime.getRuntime().addShutdownHook()
这是最基础、最通用的方式,Java 1.3+ 就开始支持。
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("执行优雅停机逻辑...");
// 关闭线程池、释放数据库连接、关闭文件等
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}));
- 触发条件:程序正常退出、
System.exit()、Ctrl+C、SIGTERM信号 - 不触发条件:
kill -9、Runtime.halt()、JVM 崩溃
Spring Boot 原生支持(最常用)
Spring Boot 3+ 内置了对优雅停机的支持,0+ 可以通过配置实现。
1 配置方式(application.yml)
server:
shutdown: graceful # 开启优雅停机
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # 最大等待时间
2 工作原理
- 停止接收新请求
- 等待当前正在处理的请求完成(不超过
timeout-per-shutdown-phase) - 触发
@PreDestroy、DisposableBean.destroy()等生命周期回调 - 最后关闭容器
3 代码中监听停机事件
@Component
public class GracefulShutdownListener {
@EventListener
public void onShutdown(ContextClosedEvent event) {
System.out.println("应用正在关闭,执行清理...");
// 关闭自定义线程池、连接池等
}
}
Spring Cloud / 微服务场景
对于微服务架构,需要配合注册中心实现服务下线通知:
@PreDestroy
public void deregisterFromRegistry() {
// 1. 从 Eureka / Nacos 等注册中心下线
// 2. 等待一段时间让负载均衡器感知(5-10s)
// 3. 再关闭容器
}
工具推荐:
- Spring Cloud 的
spring-cloud-starter-netflix-eureka-client自带优雅下线逻辑
Web 容器级别支持
1 Tomcat(Spring Boot 内嵌)
Spring Boot 2.3+ 通过 ServletWebServerFactory 自动配置了优雅停机。
手动配置(更低层级):
@Bean
public GracefulShutdown tomcatGracefulShutdown(TomcatServletWebServerFactory factory) {
GracefulShutdown gracefulShutdown = new GracefulShutdown();
factory.addConnectorCustomizers(connector -> {
connector.addLifecycleListener(gracefulShutdown);
});
return gracefulShutdown;
}
2 Undertow(高性能场景)
server: shutdown: graceful
Undertow 的优雅停机性能通常优于 Tomcat。
使用信号处理(Linux/Unix)
Java 可以捕获操作系统信号(如 SIGTERM)来实现更精细的控制:
Signal.handle(new Signal("TERM"), signal -> {
System.out.println("收到 SIGTERM,开始优雅关闭...");
// 你的关闭逻辑
System.exit(0);
});
注意:JDK 9+ 对信号处理更加稳定。
框架支持总结表
| 方式 | 支持版本 | 适用场景 | 是否需要额外代码 |
|---|---|---|---|
| ShutdownHook | Java 1.3+ | 通用、简单应用 | 需要写回调逻辑 |
| Spring Boot | 3+(配置)、全版本(代码) | Spring 应用 | 只需配置或 @EventListener |
| Tomcat | 嵌入式 9+ | Web 应用 | Spring Boot 自动配置 |
| 信号处理 | Java 所有版本 | Linux 部署、容器环境 | 需要注册 SignalHandler |
| Spring Cloud | 长期支持 | 微服务 | 需配合注册中心 |
生产环境最佳实践
# 1. 开启优雅停机
server.shutdown: graceful
spring.lifecycle.timeout-per-shutdown-phase: 30s
# 2. Dockerfile 中确保使用 SIGTERM 而不是 SIGKILL
STOPSIGNAL SIGTERM
# 3. Kubernetes 中配置 preStop hook(额外保障)
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10 && kill -15 1"]
核心检查清单:
- ✅ 线程池关闭前等待当前任务完成
- ✅ 数据库连接池在关闭前释放
- ✅ 消息队列消费者在关闭前完成 ack
- ✅ 注册中心服务下线通知
- ✅ 设置合理的超时时间(防止无限等待)
这样配置后,你的 Java 应用可以实现标准的 Kubernetes SIGTERM → 优雅停机 → 超时后 SIGKILL 的完整流程。