Spring Boot 应用在停机时如果被强制结束进程,正在处理的 HTTP 请求会立刻中断,数据库连接和线程池也无法有序释放。要解决这个问题,常见做法并不是自己编写停机接口,而是整合 Spring Boot Actuator 自带的 shutdown 端点,并配合优雅停机配置。shutdown 端点本质上是一个 HTTP 接口,调用后会让 Spring 容器开始关闭流程;优雅停机则决定关闭流程是等待请求完成还是立即停止。下面先解释 EnableShutdown 的概念,再逐步演示配置方式。

一、EnableShutdown 到底指什么
Spring Boot 本身没有名为 EnableShutdown 的独立注解,这个说法多数来自对 Actuator 中 shutdown 端点开关配置的简称。当我们在 application.yml 中写入 management.endpoint.shutdown.enabled=true 时,就相当于启用了该端点。它属于 Spring Boot Actuator 提供的运维特性之一,作用是允许向应用发送一个 HTTP POST 请求,触发 Spring 容器的关闭流程。
与操作系统信号相比,通过 HTTP 端点关闭有明确的好处:调用方可以携带安全认证信息,关闭动作能记录到审计日志,并且可以在关闭前执行容器生命周期回调。相比之下,kill -TERM 虽然也会触发 JVM 关闭钩子,但在分布式环境中无法统一通过配置中心或脚本接口进行权限控制。
需要注意的是,shutdown 端点在 Spring Boot 2.x 及之后的版本中默认是禁用的,即使引入 Actuator 也不会直接暴露,因此需要显式打开和暴露。这个设计能避免误操作把生产环境随意停掉。
二、整合 Shutdown 端点的完整配置
第一步是引入 Actuator 依赖。以 Maven 项目为例,在 pom.xml 中加入如下内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第二步在配置文件中启用并暴露 shutdown 端点。这里需要同时配置 enabled 和 exposure,两者缺一不可:
management:
endpoint:
shutdown:
enabled: true
endpoints:
web:
exposure:
include: shutdown
完成配置后启动应用,可以使用 curl 发送 POST 请求触发关闭:
curl -X POST http://localhost:8080/actuator/shutdown
如果请求成功,接口会返回类似 {"message":"Shutting down, bye..."} 的 JSON 响应,随后 Spring 容器开始关闭。如果只配置 enabled 而不配置 exposure,端点不会被 Web 层暴露,调用会返回 404;如果把 include 写成 *,则会暴露所有 Actuator 端点,生产环境并不推荐这样做。
三、配置优雅停机让请求处理完再退出
只启用 shutdown 端点还不够。默认情况下,当 Spring Boot 收到关闭请求时,内嵌容器会直接停止接收新请求,并立即中断正在处理的请求。对于包含事务、文件写入或远程调用的业务来说,这可能造成数据不一致。可以通过开启优雅停机来缓解这个问题:
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
将 server.shutdown 设置为 graceful 后,Tomcat、Jetty 或 Undertow 会先停止接收新连接,然后等待活动请求在超时时间内完成。spring.lifecycle.timeout-per-shutdown-phase 用于限制整个关闭阶段的最大时长,超过这个时间后强制停止,避免应用因为某个请求长时间阻塞而无法退出。
优雅停机只解决了请求层面的等待,业务自身的资源清理还需要借助 Spring 的生命周期回调。可以在 Bean 中使用 @PreDestroy 注解来执行缓存落盘、连接释放等操作:
@Component
public class OrderBufferCleaner {
private static final Logger log = LoggerFactory.getLogger(OrderBufferCleaner.class);
@PreDestroy
public void flushBuffer() {
log.info("开始刷新本地订单缓存");
// 执行缓存落盘或事务提交
}
}
当 Spring 容器关闭时,被 @PreDestroy 标注的方法会自动执行。除此之外,实现 DisposableBean 接口或 SmartLifecycle 的 stop() 方法也能达到类似效果。需要特别注意的是,这些回调只在正常关闭流程中生效,如果进程被 kill -9 强制结束,JVM 不会执行清理逻辑,因此生产环境建议同时配合容器的优雅终止机制。
四、生产环境的安全加固
shutdown 端点一旦通过 Web 暴露,任何能访问到管理端口的人都可以关闭服务,因此必须加上权限控制。推荐引入 spring-boot-starter-security,并针对 /actuator/shutdown 路径配置角色认证。一个简单的示例配置如下:
@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/shutdown").hasRole("ADMIN")
.anyRequest().permitAll()
)
.httpBasic();
return http.build();
}
}
上面的配置表示只有拥有 ADMIN 角色的用户才能调用 shutdown 端点,其他请求仍然放行。实际项目中还可以结合 OAuth2、JWT 或自定义登录页。除了认证之外,更稳妥的方式是将管理端口独立出来,监听在本地回环地址:
management:
server:
port: 8081
address: 127.0.0.1
这样外部流量无法直接访问管理端口,结合防火墙或安全组规则,可以进一步降低 shutdown 端点被滥用的风险。如果应用部署在 Kubernetes 中,还应配置合理的 terminationGracePeriodSeconds,让 Pod 在收到终止信号后有足够时间完成优雅停机。
在 Spring Boot 中整合 EnableShutdown 并不是单一注解配置,而是需要同时完成端点启用、Web 暴露、优雅停机和安全控制。测试环境可以通过 curl POST 触发关闭,生产环境建议使用 HTTPS、独立管理端口和角色权限保护。最终目标是让应用在退出时有序完成请求处理和资源释放,而不是简单粗暴地中断进程。
Spring BootEnableShutdown优雅停机修改时间:2026-08-27 02:33:32