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應用服務