1. 概述
生产环境中管理Spring Boot应用的生命周期至关重要。Spring容器通过ApplicationContext
负责所有Bean的创建、初始化和销毁。本文聚焦于生命周期中的销毁阶段,探讨多种关闭Spring Boot应用的方法。
关于Spring Boot项目搭建,可参考Spring Boot Starter或Spring Boot配置。
2. 使用Actuator关闭接口
Spring Boot默认启用所有Actuator接口,但/shutdown
接口除外。需添加以下Maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
若需安全控制,还需添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
在application.properties
中启用关闭接口:
management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true
endpoints.shutdown.enabled=true
⚠️ 注意:必须显式暴露需要使用的Actuator接口。上述配置暴露了所有接口,包括/shutdown
。
通过POST请求关闭应用:
curl -X POST localhost:port/actuator/shutdown
其中port
为Actuator端口。
3. 关闭应用上下文
直接调用应用上下文的close()
方法也能关闭应用:
ConfigurableApplicationContext ctx = new
SpringApplicationBuilder(Application.class).web(WebApplicationType.NONE).run();
System.out.println("Spring Boot应用已启动");
ctx.getBean(TerminateBean.class);
ctx.close();
此操作会销毁所有Bean、释放锁并关闭Bean工厂。通过@PreDestroy
注解验证关闭过程:
public class TerminateBean {
@PreDestroy
public void onDestroy() throws Exception {
System.out.println("Spring容器已销毁!");
}
}
需注册该Bean:
@Configuration
public class ShutdownConfig {
@Bean
public TerminateBean getTerminateBean() {
return new TerminateBean();
}
}
执行后输出:
Spring Boot应用已启动
Closing AnnotationConfigApplicationContext@39b43d60
DefaultLifecycleProcessor - Stopping beans in phase 0
Unregistering JMX-exposed beans on shutdown
Spring容器已销毁!
⚠️ 踩坑:关闭子上下文不会影响父上下文,因它们生命周期独立。
3.1 关闭当前应用上下文
前例创建了子上下文后关闭。若要关闭当前上下文,可:
- 调用Actuator的
/shutdown
接口 - 自定义关闭接口:
@RestController
public class ShutdownController implements ApplicationContextAware {
private ApplicationContext context;
@PostMapping("/shutdownContext")
public void shutdownContext() {
((ConfigurableApplicationContext) context).close();
}
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.context = ctx;
}
}
通过ApplicationContextAware
获取当前上下文,在接口中调用close()
:
curl -X POST localhost:port/shutdownContext
✅ 生产环境使用此类接口务必添加安全控制!
4. 使用SpringApplication退出
SpringApplication
会向JVM注册关闭钩子确保应用正常退出。Bean可实现ExitCodeGenerator
返回特定错误码:
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class)
.web(WebApplicationType.NONE).run();
int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
@Override
public int getExitCode() {
// 返回错误码
return 0;
}
});
System.exit(exitCode);
Java 8 Lambda写法:
SpringApplication.exit(ctx, () -> 0);
调用System.exit(exitCode)
后程序以指定码退出:
Process finished with exit code 0
5. 终止应用进程
通过外部脚本关闭应用。首先让应用上下文将PID写入文件:
SpringApplicationBuilder app = new SpringApplicationBuilder(Application.class)
.web(WebApplicationType.NONE);
app.build().addListeners(new ApplicationPidFileWriter("./bin/shutdown.pid"));
app.run();
创建shutdown.bat
脚本:
kill $(cat ./bin/shutdown.pid)
脚本从shutdown.pid
读取进程ID并使用kill
命令终止应用。
6. 总结
本文介绍了五种关闭Spring Boot应用的方法,开发者应根据场景选择:
方法 | 适用场景 | 优点 |
---|---|---|
/shutdown 接口 |
需HTTP远程控制 | 简单粗暴,支持外部调用 |
close() 方法 |
编程式控制 | 直接操作上下文,适合内部逻辑 |
SpringApplication.exit() |
需传递退出码 | 与JVM交互,支持错误码传递 |
终止进程 | 外部脚本管理 | 支持重启/启动等完整生命周期控制 |
✅ 最佳实践:
- 需远程控制用
/shutdown
接口 - 需错误码传递用
exit()
- 脚本管理用PID文件
- 其他场景用
close()
足够
完整代码见GitHub项目。