在实际的Java项目部署中,我们常常需要将打包好的SpringBoot应用交付给用户,并确保服务能够方便、可靠地启动和停止。一个常见的需求是:如何让非技术用户也能一键优雅地停止服务?SpringBoot框架原生提供的能力,可以优雅地解决这个问题。
一、服务启动实现
通常,我们拿到一个SpringBoot应用的Jar包后,可以通过一行简单的命令启动它:
nohup java -jar demo-springboot-0.0.1.jar
nohup:意为“no hang up”(不挂断)。它的核心作用是让命令在后台运行,并且不受当前终端(SSH连接)关闭的影响。默认情况下,命令的输出会被重定向到当前目录下的nohup.out文件中。
为了提高易用性,我们通常会将启动命令封装到一个Bash脚本(例如 start.sh)中,方便用户执行。
二、服务停止实现
停止服务时,我们通常会使用 ps -ef | grep java 这类命令来查找并终止进程。但对于普通用户而言,在一堆进程里精准地找到目标应用并杀死它,无疑是一个挑战。
解决这个问题的核心思路很清晰:在服务启动时,将当前进程的PID(进程ID)写入一个指定的文件;在停止服务时,通过读取这个文件获取PID,然后执行终止操作。 整个过程同样可以封装到一个 stop.sh 脚本中,实现一键停止。
最初我打算手动实现这个PID写入逻辑,但在编写脚本时惊喜地发现,SpringBoot已经为我们提供了一个现成的解决方案:ApplicationPidFileWriter 监听器,完全无需重复造轮子。
一个正确的 stop.sh 脚本示例如下:
#!/bin/bash
PID=$(cat demo.pid)
kill -15 $PID # 发送SIGTERM信号,允许应用执行资源清理等收尾工作
rm -f demo.pid # 删除PID文件
ApplicationPidFileWriter核心特性
这个监听器设计得非常周到,具备以下优点:
- 生命周期感知:它会在SpringBoot应用上下文完全准备好、即服务成功启动后,才去获取并写入PID。这避免了在应用初始化失败时写入无效的PID。
- 写入逻辑简洁可靠:它仅仅将纯数字的PID写入到指定的
.pid文件中,文件内容只有一行,便于脚本读取和解析。
- 内置完善的异常处理:它自动处理了IO异常、目标路径的父目录不存在则自动创建、以及覆盖旧的PID文件等细节。开发者无需编写任何额外的文件操作代码。
- 确保PID一致性:它获取的PID与操作系统层面
ps 命令查询到的PID、以及SpringBoot ApplicationPid.getPid() 方法的返回值完全一致,保证了停止命令能够精准定位到目标进程。
快速配置方式
在SpringBoot应用中启用PID文件写入功能,有两种简便的配置方式:
-
在启动类中添加监听器(代码配置):
public static void main(String[] args) {
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addListeners(new ApplicationPidFileWriter("demo.pid")); // 指定PID文件路径
application.run(args);
}
-
通过配置文件指定(SpringBoot 2.x及以上版本支持):
在 application.properties 或 application.yaml 中添加配置即可,无需修改任何代码。
# application.properties
spring.pid.file=demo.pid
结合启动和停止脚本,我们就构建了一套简洁、高效且适用于生产环境的服务启停方案。这种方法不仅降低了运维门槛,也使得应用的生命周期管理更加规范。如果你想了解更多关于后端开发与部署的实战技巧,欢迎在云栈社区交流讨论。
|