Spring Boot提供了2种优雅关闭进程的方式:html
基于管理端口方式实现进程关闭其实是模块spring-boot-actuator
提供的功能。java
首先,须要在项目中添加对应模块依赖配置。web
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
dependencies { compile("org.springframework.boot:spring-boot-starter-actuator") }
其次,在配置文件中添加对应的参数配置(以文件application.properties为例说明)。spring
# 容许执行关闭操做 management.endpoint.shutdown.enabled=true # 处于安全考虑,只容许在本地指定关闭操做 management.server.address=127.0.0.1 # 管理端口 management.server.port=8000 # 管理URL基础路径,默认为“/” management.endpoints.web.base-path=/ops # 配置关闭进程Endpoint management.endpoints.web.path-mapping.shutdown=shutdown # 对外暴露管理Endpoint management.endpoints.web.exposure.include=info, health, shutdown
完成上述准备工做之后,启动Spring Boot应用,经过调用POST http://localhost:8000/ops/shutdown
便可关闭进程。shell
实践中一般将上述关闭进程的URL调用写到脚本中,同时还能够结合别的方式一块儿确保进程必定能退出,以下为脚本示例(pname指进程名称):ubuntu
#!/bin/bash # 先经过管理端口关闭进程 curl -X POST http://127.0.0.1:8000/ops/shutdown --connect-timeout 3 --max-time 5 # 再次经过名称检查进程是否被成功中止 count=`ps -ef |grep pname |grep -v "grep" |wc -l` if [ $count -gt 0 ]; then if [ -f "$pid_file" ]; then # 若是存在进程ID文件,则读取进程ID使用信号量通知方式关闭进程 pid=`cat $pid_file` kill -15 $pid else # 经过名称方式查找到进程ID,使用信号量通知方式关闭进程 pid=`ps -ef |grep pname |grep -v "grep"| awk '{print $2}'` kill -15 $pid fi fi
关于经过管理端口关闭Spring Boot进程的详细说明参见:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready-endpoints 。安全
Spring Boot支持直接将打包好的可执行jar包以系统服务方式运行,具体实现方式以下所述。bash
首先,将应用打包为彻底可执行的jar包。app
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!-- 这个配置很是重要,使打包好的jar包具有可执行权限--> <executable>true</executable> </configuration> </plugin>
bootJar { launchScript() }
其次,将打包好的应用jar包添加为系统服务(在ubuntu18.04 LTS上实现,基于systemd)curl
1.假设将Spring Boot应用安装到/var/myapp目录下:将上述打包好的jar包拷贝到/var/myapp(目录不存在,手动建立)
2.在/etc/systemd/system下添加指定名称的系统服务:myapp.service,内容以下:
[Unit] Description=myapp After=syslog.target [Service] User=root ## 注意:这里配置的是未来启动该服务的Linux系统用户名,影响权限 ExecStart=/var/myapp/myapp.jar SuccessExitStatus=143 [Install] WantedBy=multi-user.target
3.启动服务
$ sudo systemctl enable myapp.service $ sudo systemctl start myapp.service
若是须要查看应用启动日志,请执行:$ journalctl -f
。
若是启动服务失败,请检查对应名称的服务文件是否放在正确位置(如:systemd系统须要放在/etc/systemd/system目录下),或者检查启动服务的用户权限,一些错误情形能够参考:https://springjavatricks.blogspot.com/2018/06/installing-spring-boot-services-in.html 。
关于将Spring Boot应用部署为系统服务的详细说明参见: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#deployment-install 。
我在如何优雅地中止Java进程中有讲到如何实如今进程退出以前作一些收尾的工做,这在Spring Boot中一样适用,只须要监听对应的信号量并注册JVM关闭钩子便可。
@SpringBootApplication public class SpringbootApplication { private static final Logger logger = LoggerFactory.getLogger(SpringbootApplication.class); public static void main(String[] args) { // 在Spring Boot应用中经过监听信号量和注册关闭钩子来实如今进程退出以前执行收尾工做 // 监听信号量 Signal sg = new Signal("TERM"); Signal.handle(sg, new SignalHandler() { @Override public void handle(Signal signal) { logger.info("do signal handle: {}", signal.getName()); System.exit(0); } }); // 注册关闭钩子 Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run() { // 执行收尾工做 logger.info("do something on shutdown hook"); } }); SpringApplication.run(SpringbootApplication.class, args); logger.info("Start DONE."); } }
另外,须要注意的是:在普通的Java应用程序中,当出现RuntimeExeception或OOM时会触发关闭钩子的执行;可是在Spring Boot应用中,当出现RuntimeException或OOM时并不会触发关闭钩子的执行(Spring Boot使用了嵌入式Tomcat)。
【参考】
https://www.jianshu.com/p/44ef43b282f0 正确、安全地中止SpringBoot应用服务