前言
在生產環境下管理Spring Boot應用的生命周期非常重要。Spring容器通過ApplicationContext處理應用服務的所有的beans的創建、初始化、銷毀。
本文着重於生命周期中的銷毀階段的處理,我將使用多種方式來實現關閉Spring Boot應用服務。如果你需要了解關於Spring Boot更多內容,請看我之前寫過的文章和精品合輯!
一、通過Actuator Shutdown 端點服務
Spring Boot Actuator是一個主要用於應用指標監控和健康檢查的服務。可以通過Http訪問對應的Endpoint來獲取應用的健康及指標信息。另外,它還提供了一個遠程通過http實現應用shutdown的端點。
首先,我們要在Spring Boot中引入Actuator。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
生產環境通常出於安全考慮,不能將應用關閉的訪問完全公開,我們還要引入spring-boot-starter-security。具體的安全配置,請參考學習Spring security,在此不多做敘述!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
默認情況下,出於安全考慮shutdown端點服務是處於關閉狀態的,我們需要通過配置開啟:
management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true
endpoints.shutdown.enabled=true
至此,我們就可以通過發送一個Post請求,來停掉Spring Boot應用服務。
curl -X POST localhost:port/actuator/shutdown
這種方法的缺陷在於:當你引入Actuator的shutdown服務的時候,其他的監控服務也自動被引入了。
二、 關閉Application Context
我們也可以自己實現一個Controller開放訪問端點,調用Application Context的close方法實現應用服務的關閉。
@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;
}
}
我們添加了一個Controller繼承自ApplicationContextAware接口,並且重寫了setApplicationContext方法獲取當前的應用上下文。然后在Post請求方法中調用close方法關閉當前應用。這種實現的方法更加輕量級,不會像Actuator一樣引入更多的內容。我們同樣可以通過發送Post請求,實現應用的關閉。
curl -X POST localhost:port/shutdownContext
同樣,當你對外開放一個關閉服務的端點,你要考慮它的權限與安全性
四、退出 SpringApplication
還可以通過SpringApplication 向JVM注冊一個 shutdown 鈎子來確保應用服務正確的關閉。
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class)
.web(WebApplicationType.NONE).run();
int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
@Override
public int getExitCode() {
// return the error code
return 0;
}
});
System.exit(exitCode);
同樣的效果,使用Java 8 lambda可以這樣實現,代碼簡單很多:
SpringApplication.exit(ctx, () -> 0);
五、kill殺掉應用進程
我們還可以使用bat或者shell腳本來停止應用的進程。所以,我們首先在應用啟動的時候,要把進程ID寫到一個文件里面。如下所示:
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)
然后調用這個腳本就可以把應用服務進程殺死。
期待您的關注
- 博主最近新寫了一本書:《手摸手教您學習SpringBoot系列-16章97節》
- 本文轉載注明出處(必須帶連接,不能只轉文字):字母哥博客。