起因
- spring boot默認是不會優雅關閉的,這樣就導致在重啟時會將正在運行的程式打斷,導致故障發生,
當前解決方式
- 引入
spring-boot-starter-actuator監控類別庫,它其中一個功能支持優雅關閉, - spring boot 2.3版本開始,自己集成了優雅關閉,無需再引入上方類別庫即可實作優雅關閉,
坑爹的地方
spring-boot-starter-actuator檔案中說是支持優雅關閉,但僅僅是spring層面上的,不和tomcat等容器掛鉤,直到spring boot 2.3開啟自帶的優雅關閉后才真正能實作,也就是說2.3之前的版本根本實作不了優雅關閉,需要自己來進一步按照使用的容器做處理才行,參考這個issue:Allow the embedded web server to be shut down gracefully,- 2.3以上版本,如果是在linux下,發送命令
kill -2 xxx可以觸發優雅關閉,但是在windows下,只有ctrl+c才能觸發(可以在idea下用run里面的exit按鈕模擬),但windows下我們一般是用服務來運行,所以永遠無法觸發ctrl+c,因此即便是2.3版本后,windows下也必須安裝spring-boot-starter-actuator來通過發送http請求來實作優雅關閉,
2.3以上版本的處理方法(如果是用tomcat容器需要9.0.33以上)
- 在
application.yml中增加:# 開啟優雅關閉 server: shutdown: graceful # 配置強制結束時間,不配置的話默認30s spring: lifecycle: timeout-per-shutdown-phase: 30s - 配置好后就支持優雅關閉了,linux端只需要在
systemctl的組態檔中設定關閉命令是kill -2 xxxPID,pid可以通過檔案或命令根據埠查找什么的,手頭上暫沒有linux來測驗,后期有了后補上完整腳本, - widows端雖然也支持,但是如果用服務方式運行是沒法觸發ctrl+c相同的效果的,所以還是不行,
2.3以下的處理方法(或者是2.3版本以上的windows端)
- 引入
spring-boot-starter-actuator的maven類別庫<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> - 在
application.yml中增加:
發送請求的路徑是這樣的:#監控相關配置 management: endpoint: # 開啟 shutdown: enabled: true endpoints: web: # 只允許shutdown,為了安全,其它想要監控自行配置 exposure: include: "shutdown" # 自定義請求路徑,為了安全 base-path: /xxx server: #自定義請求埠,為了安全 port: 7080curl -X POST http://localhost:自定義埠/自定義路徑/shutdown,由于路徑和埠都是自定義的,所以安全性方面不用太過擔心, - 分支1:如果是2.3版本以上的windows端,再開啟自帶的優雅關閉,就可以通過http請求來實作了
# 開啟優雅關閉 server: shutdown: graceful # 配置強制結束時間,不配置的話默認30s spring: lifecycle: timeout-per-shutdown-phase: 30s - 分支2:如果是2.3以下版本,此時雖然可以發送http請求來關閉,但實際上不會等待正在執行的程式,而是會直接關閉,還應該配置容器相關,以tomcat容器為例:
- 創建相關類:
package xxx.xxx.xxx; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.connector.Connector; import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 優雅關閉 */ @Slf4j public class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> { private volatile Connector connector; /** * 30s強制關閉 */ private static final int TIMEOUT = 30; /** * 自定義鏈接 * * @param connector */ @Override public void customize(Connector connector) { this.connector = connector; } /** * 關閉時觸發 * * @param event */ @Override public void onApplicationEvent(ContextClosedEvent event) { this.connector.pause(); Executor executor = this.connector.getProtocolHandler().getExecutor(); if (executor instanceof ThreadPoolExecutor) { try { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; threadPoolExecutor.shutdown(); if (!threadPoolExecutor.awaitTermination(TIMEOUT, TimeUnit.SECONDS)) { log.warn("Tomcat thread pool did not shut down gracefully within " + "30 seconds. Proceeding with forceful shutdown"); } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } }- 在啟動類中引入:
package xx.xxx.xxx; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.context.annotation.Bean; @SpringBootApplication public class XxxxApplication { /** * 優雅關閉bean * @return */ @Bean("gracefulShutdown") public GracefulShutdown gracefulShutdown() { return new GracefulShutdown(); } /** * tomcat配置優雅關閉 * @param gracefulShutdown * @return */ @Bean public ConfigurableServletWebServerFactory webServerFactory(@Qualifier("gracefulShutdown") GracefulShutdown gracefulShutdown) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.addConnectorCustomizers(gracefulShutdown); return factory; } public static void main(String[] args) { SpringApplication.run(XxxxApplication .class, args); } } - 以上配置后再發送http請求才會優雅關閉,但僅適用于tomcat容器,undertow容器可以參考這個:Spring boot 2.0 之優雅停機
- 創建相關類:
windows端用winsw設定為服務運行時的配置
- winsw可以從這里下載:winsw,主要作用就是可以讓程式以服務的方式后臺運行并能開機啟動等
- 需要下載windows下的curl,地址:curl for Windows
- 配置winsw的config檔案:
<service> <!-- ID of the service. It should be unique across the Windows system--> <id>XXX</id> <!-- Display name of the service --> <name>xxx</name> <!-- Service description --> <description>xxx名稱(powered by WinSW)</description> <!-- Path to the executable, which should be started --> <env name="JAVA_HOME" value="https://www.cnblogs.com/vishun/p/%JAVA_HOME%"/> <executable>java</executable> <startarguments>-jar -Xms128m -Xmx512m "D:\jar包路徑\xxx.jar"</startarguments> <!--停止 --> <stopexecutable>D:\curl路徑\bin\curl.exe</stopexecutable> <stoparguments>-X POST http://localhost:7080/xxx/shutdown</stoparguments> <!--不配置的話默認15s--> <stoptimeout>30 sec</stoptimeout> <startmode>Automatic</startmode> <logmode>none</logmode> </service>
結束
- 以上,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/354414.html
標籤:Java
