1. 概述
在關閉時,Spring 的 TaskExecutor 默認情況下會中斷所有正在運行的任務。但是,有時可能需要它等待所有正在運行的任務完成。這 為每個任務提供機會,以確保關閉過程安全。
在本快速教程中,我們將學習如何以更優雅的方式關閉 Spring Boot 應用程序,尤其是在涉及使用線程池執行的任務時。
2. 簡單示例
讓我們考慮一個簡單的 Spring Boot 應用。我們將自動注入默認的 TaskExecutor 實例:
@Autowired
private TaskExecutor taskExecutor;在應用程序啓動時,我們使用線程池中的一個線程執行一個 1 分鐘長的過程:
taskExecutor.execute(() -> {
Thread.sleep(60_000);
});當啓動過程啓動後 20 秒,例如,啓動後 20 秒,則示例中的線程會被中斷,應用程序會立即關閉。
3. 等待任務完成
通過創建自定義的 <em >ThreadPoolTaskExecutor</em> Bean,來修改默認的任務執行器行為。
該類提供了一個標誌 <em >setWaitForTasksToCompleteOnShutdown</em>,用於防止在關閉時中斷正在運行的任務。 將其設置為 <em >true</em>:
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(2);
taskExecutor.setMaxPoolSize(2);
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
taskExecutor.initialize();
return taskExecutor;
}此外,我們將重構之前的邏輯,創建3個線程,每個線程執行一個1分鐘長的任務。
@PostConstruct
public void runTaskOnStartup() {
for (int i = 0; i < 3; i++) {
taskExecutor.execute(() -> {
Thread.sleep(60_000);
});
}
}現在,我們將在啓動後 60 秒內啓動關機過程。
我們發現應用程序在啓動後 120 秒才關閉。池大小為 2 僅允許兩個同時執行的任務,因此第三個任務被排隊等待。
設置該標誌項可確保當前正在執行的任務以及排隊等待的任務都能完成。
請注意,當收到關機請求時,任務執行器關閉隊列,從而防止新的任務被添加。
4. 終止前的最大等待時間
儘管我們配置了等待正在進行和排隊的任務完成,Spring 仍然會繼續關閉容器的其他部分。 這可能會釋放執行器需要的資源,導致任務失敗。
為了阻止容器的其他部分關閉,我們可以為 ThreadPoolTaskExecutor 指定最大等待時間。
taskExecutor.setAwaitTerminationSeconds(30);這確保了在指定的時間段內,容器級別的關機過程將被阻止。
當我們將setWaitForTasksToCompleteOnShutdown標誌設置為true時,我們需要指定一個顯著更高的超時時間,以便隊列中所有剩餘的任務也被執行完畢。
5. 結論
在本快速教程中,我們學習瞭如何安全地關閉 Spring Boot 應用程序,通過配置任務執行者 Bean,確保正在運行和提交的任務在應用程序結束時完成。 這樣可以保證所有任務都有足夠的時間完成其工作。
一個顯而易見的副作用是,它也可能導致關閉階段更長。 因此,我們需要根據應用程序的性質來決定是否使用它。