Spring Boot 應用優雅停機與資源清理:深入理解關閉鉤子

在開發和部署 Spring Boot 應用程序時,除了關注其啟動和運行,理解如何實現**優雅停機(Graceful Shutdown)**也同樣至關重要。優雅停機意味著在應用程序關閉時,能夠有序地釋放資源、完成正在進行的任務,并避免數據丟失或損壞。本文將深入探討 Spring Boot 中與優雅停機相關的機制,特別是 JVM 關閉鉤子以及如何自定義清理邏輯。

1. 什么是 Spring Boot 的關閉鉤子?

在 Spring Boot 應用程序的啟動過程中,你可能會注意到類似以下的代碼片段(通常在 SpringApplication.class 中):

// ... existing code ...
if (this.properties.isRegisterShutdownHook()) {SpringApplication.shutdownHook.enableShutdownHookAddition();
}
// ... existing code ...

這段代碼的核心在于 this.properties.isRegisterShutdownHook()。它對應于 Spring Boot 配置中的 spring.main.register-shutdown-hook 屬性。

  • spring.main.register-shutdown-hook: 這個配置屬性(默認為 true)決定了 Spring Boot 應用程序是否會在 JVM 啟動時注冊一個關閉鉤子(Shutdown Hook)
  • SpringApplication.shutdownHook.enableShutdownHookAddition(): 當 spring.main.register-shutdown-hooktrue 時,此方法會被調用,它負責向 JVM 運行時環境注冊一個鉤子。當 JVM 接收到外部的關閉信號(如 Ctrl+Ckill <pid> 命令等,而非強制終止的 kill -9)時,這個鉤子就會被激活。

簡而言之,注冊關閉鉤子的目的是讓 Spring Boot 有機會在 JVM 正常關閉前,執行一系列預定義的清理操作,從而確保應用程序的優雅停機。 這些操作可能包括關閉數據庫連接池、釋放文件句柄、停止后臺線程等。

2. 如何自定義關閉時的清理邏輯?

Spring Boot 提供了靈活的機制來允許開發者在應用程序關閉時執行自定義的清理邏輯。主要有兩種常用且推薦的方式:監聽 ContextClosedEvent 和使用 @PreDestroy 注解。

2.1 監聽 ContextClosedEvent

這是最推薦的方式,因為它與 Spring 應用程序上下文的生命周期事件緊密集成。當 Spring 應用程序上下文完成其所有 Bean 的銷毀并準備關閉時,會發布 ContextClosedEvent

如何定義:

  1. 創建一個實現 org.springframework.context.ApplicationListener<ContextClosedEvent> 接口的類。
  2. onApplicationEvent 方法中編寫你的全局清理邏輯。
  3. 使用 @Component 注解將其注冊為 Spring Bean。

示例:

// src/main/java/com/dosun/demo01/listener/MyCleanupListener.java
package com.dosun.demo01.listener;import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;@Component
public class MyCleanupListener implements ApplicationListener<ContextClosedEvent> {@Overridepublic void onApplicationEvent(ContextClosedEvent event) {System.out.println("應用程序上下文已關閉。執行自定義清理邏輯...");// 在這里編寫你的自定義清理邏輯,例如:// 1. 關閉數據庫連接// 2. 釋放文件句柄// 3. 停止線程池// 4. 清理緩存等System.out.println("自定義清理邏輯執行完畢。");}
}

當應用程序正常關閉時,onApplicationEvent 方法會被調用,從而執行你在其中定義的清理代碼。

2.2 使用 @PreDestroy 注解

對于 Spring 容器管理的特定 Bean,你可以使用 @PreDestroy 注解來標記一個方法。這個方法會在該 Bean 被銷毀之前執行。這對于 Bean 級別的資源清理非常有用。

如何定義:

在任何 Spring 管理的 Bean 中,在你希望執行 Bean 特定清理邏輯的方法上添加 @PreDestroy 注解。

示例:

package com.dosun.demo01.service;import org.springframework.stereotype.Service;
import jakarta.annotation.PreDestroy;@Service
public class MyService {public MyService() {System.out.println("MyService Bean 已創建。");}@PreDestroypublic void cleanup() {System.out.println("MyService Bean 即將被銷毀。執行 Bean 級別的清理邏輯...");// 在這里編寫 MyService 特定的清理邏輯,例如關閉 MyService 內部的連接System.out.println("MyService Bean 級別的清理邏輯執行完畢。");}public void doSomething() {System.out.println("MyService 正在執行一些操作。");}
}

2.3 如何選擇?

  • ContextClosedEvent: 適用于需要在整個應用程序關閉時執行的全局清理任務。它在所有 Bean 都被銷毀之后,但在 JVM 真正退出之前執行。例如,全局的日志系統清理、一些共享資源的釋放等。
  • @PreDestroy: 適用于特定 Bean 的清理任務。它在該 Bean 被銷毀之前執行。例如,某個 Bean 內部持有的數據庫連接、線程池、文件句柄等資源的釋放。

在大多數情況下,監聽 ContextClosedEvent 會是更靈活和通用的選擇,因為你可以在一個地方集中管理所有應用程序級別的關閉邏輯。

3. spring.main.register-shutdown-hookfalse 的影響

現在我們來討論一個關鍵問題:如果 spring.main.register-shutdown-hook 被設置為 false,清理鉤子是不是就不生效了?

答案是:是的,在大多數情況下,自定義的清理鉤子將不會生效,或者說無法在應用程序接收到正常關閉信號時被優雅地觸發。

具體影響如下:

  • 對于監聽 ContextClosedEvent 的自定義清理邏輯:
    如果 spring.main.register-shutdown-hookfalse,Spring Boot 將不會向 JVM 注冊關閉鉤子。這意味著當 JVM 收到 Ctrl+Ckill <pid> 等正常的關閉信號時,Spring Boot 應用程序將無法通過其內部的關閉鉤子機制來優雅地關閉 Spring 應用程序上下文。因此,你的 MyCleanupListener 中監聽 ContextClosedEventonApplicationEvent 方法將不會被觸發

  • 對于使用 @PreDestroy 注解的方法:
    @PreDestroy 注解的方法是在 Spring Bean 被銷毀之前調用的,這是 Spring 容器生命周期的一部分。

    • 如果 Spring 應用程序上下文能夠被正常關閉(例如,你在代碼中手動調用了 SpringApplication.exit()ApplicationContext.close()),那么即使 spring.main.register-shutdown-hookfalse@PreDestroy 方法仍然會被調用。
    • 但是,在通常的場景下,如果 spring.main.register-shutdown-hookfalse,并且你期望通過操作系統信號(如 Ctrl+C)來關閉應用程序,那么 JVM 不會通知 Spring 執行其關閉邏輯。Spring 容器就無法執行其正常的銷毀流程,包括調用 @PreDestroy 方法。應用程序可能會突然終止,導致資源未釋放,數據不一致等問題。

總結來說:

spring.main.register-shutdown-hook 配置是 Spring Boot 實現應用程序優雅停機的關鍵。

  • 如果設置為 true(默認值且推薦):Spring 會注冊 JVM 關閉鉤子,確保在應用程序因外部信號而關閉時,ContextClosedEvent 監聽器和 @PreDestroy 方法都能得到執行,從而進行必要的清理。
  • 如果設置為 false:Spring 將不會注冊這個 JVM 關閉鉤子。這意味著當應用程序收到 Ctrl+Ckill 等信號時,Spring 應用程序上下文將不會被優雅關閉。那些依賴 Spring 正常關閉流程的清理邏輯(包括 ContextClosedEvent 和通常情況下的 @PreDestroy)將不會生效。這可能導致應用程序資源未釋放、數據不一致等問題。

因此,在大多數生產環境中,強烈建議將 spring.main.register-shutdown-hook 保持為 true,以確保應用程序能夠以健壯和可靠的方式關閉并清理資源。這將極大地提高應用程序的穩定性和數據完整性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91749.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91749.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91749.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

淘寶扭蛋機小程序開發:重構電商娛樂化體驗的新范式

在電商行業同質化競爭加劇的當下&#xff0c;消費者對購物體驗的期待已從“功能滿足”轉向“情感共鳴”。淘寶扭蛋機小程序憑借“盲盒式隨機獎勵游戲化交互”的創新模式&#xff0c;成為撬動年輕用戶消費力的新支點。其開發邏輯不僅是對傳統電商的升級&#xff0c;更是對“娛樂…

YOLO演變史(一)

在YOLOV1發布后&#xff0c;作者并沒有滿足于此&#xff0c;而是持續對YOLO進行了改進。 YOLOV2&#xff1a;Better, Faster, Stronger YOLOv2&#xff08;又稱YOLO9000&#xff09;發表于2017年CVPR&#xff0c;是YOLO系列的第二代版本。其論文標題“Better, Faster, Stronger…

專題:2025智能體研究報告|附70份報告PDF、原數據表匯總下載

原文鏈接&#xff1a;https://tecdat.cn/?p43035 智能體正在改寫商業規則&#xff1a;某城商行的智能客服用公有云部署&#xff0c;把單筆交互成本從5.7元砍到1.2元&#xff0c;投訴率直降42%&#xff08;《賽迪智庫&#xff1a;2025全球智能體進展報告》P24&#xff09;&…

Axios 完整功能介紹和完整示例演示

Axios 是一個基于 Promise 的現代化 HTTP 客戶端庫&#xff0c;用于瀏覽器和 Node.js 環境。它提供了簡潔的 API 和強大的功能&#xff0c;是前端開發中最常用的網絡請求工具之一。核心功能 瀏覽器 & Node.js 雙平臺支持 瀏覽器中使用 XMLHttpRequestNode.js 中使用 http 模…

math.h函數

math.c函數作用 1. 基本三角函數&#xff08;參數為弧度&#xff09; sin(double x)&#xff1a;計算正弦值。cos(double x)&#xff1a;計算余弦值。tan(double x)&#xff1a;計算正切值。asin(double x)&#xff1a;反正弦&#xff08;返回值范圍&#xff1a;[-π/2, π/2]&…

在Next.js里玩轉pdf預覽

1.背景在項目開發中&#xff0c;pdf預覽是一個很常見的業務。各大公司為了保護自己的知識產權&#xff0c;也會對pdf預覽進行限制&#xff0c;比如&#xff1a;不允許下載、打印&#xff0c;不允許提取文字等等。要想在實現預覽功能的基礎上還要附加這些限制&#xff0c;有很多…

算法競賽備賽——【圖論】求最短路徑——Floyd算法

floyd算法 基于動態規劃 應用&#xff1a;求多源最短路 時間復雜度&#xff1a;n^3 dijkstra&#xff1a;不能解決負邊權 floyd&#xff1a;能解決負邊權 不能解決負邊權回路問題 求最短路徑&#xff1a;dijkstra bfs floyd 思路 1.讓任意兩點之間的距離變短&#xff1a;引入…

雙指針(滑動窗口)相關算法題

雙指針算法有時候也叫尺取法或者滑動窗口&#xff0c;是?種優化暴力枚舉策略的手段&#xff1a;當我們發現在兩層 for 循環的暴力枚舉過程中&#xff0c;兩個指針是可以不回退的&#xff0c;此時我們就可以利用兩個指針不回退的性質來優化時間復雜度。因為雙指針算法中&#x…

ScratchCard刮刮卡交互元素的實現

效果展示 刮刮卡是?種常見的網頁交互元素&#xff0c;通過模擬物理世界的刮涂層來揭示下方的內容。這種效果主要依賴于HTML5的 元素來實現。以下是?個基于TypeScript的刮刮卡實現示例&#xff0c;包括配置項、初始化方法和核心的刮開邏輯。下面是展示的效果部分刮開效果&…

【Python LeetCode 專題】熱題 100,重在思路

哈希1. 兩數之和49. 字母異位詞分組128. 最長連續序列雙指針283. 移動零11. 盛最多水的容器15. 三數之和42. 接雨水滑動窗口3. 無重復字符的最長子串438. 找到字符串中所有字母異位詞子串560. 和為 K 的子數組239. 滑動窗口最大值普通數組53. 最大子數組和56. 合并區間189. 輪轉…

openEuler 22.03 LTS Rootless Docker 安裝指南

openEuler 22.03 LTS Rootless Docker 安裝指南 1.創建普通用戶&#xff08;用于無根模式&#xff09; sudo useradd -m docker-user sudo passwd docker-user # 設置密碼 sudo usermod --add-subuids 100000-165535 docker-user sudo usermod --add-subgids 100000-165535 do…

CMake指令:常見內置命令行工具( CMake -E )

目錄 1.簡介 2.核心作用 3.常用命令介紹 3.1.文件操作命令 3.2.系統命令執行 3.3.校驗與哈希 3.4.流程控制與等待 3.5.路徑與文件處理 3.6.歸檔與壓縮 3.7.網絡與下載 3.8.實用工具 4.使用示例 5.與 shell 命令的對比 6.在 CMake 腳本中使用 7.總結 相關鏈接 1…

YOLO融合CAF-YOLO中的ACFM模塊

YOLOv11v10v8使用教程&#xff1a; YOLOv11入門到入土使用教程 YOLOv11改進匯總貼&#xff1a;YOLOv11及自研模型更新匯總 《CAF-YOLO: A Robust Framework for Multi-Scale Lesion Detection in Biomedical Imagery》 一、 模塊介紹 論文鏈接&#xff1a;https://arxiv.org…

Webpack 項目構建優化詳解

1. 相關面試題 1.1. 做過哪些Webpack打包構建優化? 代碼分割:使用 Webpack 的 SplitChunksPlugin 進行代碼分割,將第三方庫、公共代碼與業務代碼分離,提高緩存利用率和加載速度。 Tree Shaking:通過配置 mode: production 或使用 TerserPlugin,移除未引用的代碼,減少…

【深度學習基礎】張量與Tensor的區別?從標量到深度學習的多維世界

目錄引言一、張量&#xff08;Tensor&#xff09;的定義與特性1. 數學中的張量2. 深度學習中的Tensor二、標量&#xff08;Scalar&#xff09;是什么&#xff1f;三、深度學習中的其他核心量1. 向量&#xff08;Vector&#xff09;2. 矩陣&#xff08;Matrix&#xff09;3. 高階…

設計模式一: 模板方法模式 (Template Method Pattern)

模板方法模式是一種行為設計模式&#xff0c;它通過定義一個算法的骨架&#xff0c;而將一些步驟延遲到子類中實現。Template Method 使得子類可以不改變&#xff08;復用&#xff09;一個算法結構 即可重定義&#xff08;override 重寫&#xff09;該算法的某些特定步驟。基本…

Linux驅動學習day24(UART子系統)

一、UART硬件理論1.1 作用及功能UART&#xff1a;通用異步收發傳輸器&#xff0c;簡稱串口。功能&#xff1a;移植u-boot、內核時&#xff0c;主要使用串口查看打印信息。外接各種模塊&#xff0c;比如藍牙GPS模塊。使用UART的時候&#xff0c;要注意1. 波特率 2. 格式&#xf…

NFS共享服務器

目錄 任務要求 思路總結 1.NFS共享服務 服務端 (ip 192.168.48.128) 客戶端 (ip 192.168.48.130) 2.配置autofs自動掛載 任務要求 1.NFS服務器,可以讓PC將網絡中的NFS服務器共享的目錄掛載到本地端的文件系統中,而在本地端的系統中看來&#xff0c;那個遠程主機的目…

FreeRTOS學習筆記之隊列

小編正在學習嵌入式軟件&#xff0c;目前建立了一個交流群&#xff0c;可以留下你的評論&#xff0c;我拉你進群一、簡介隊列是為了任務與任務、任務與中斷之間的通信而準備的&#xff0c;可以在任務與任務、任務與中斷之間消息傳遞&#xff0c;隊列中可以存儲有限的、大小固定…

垃圾收集器-ZGC

前言在Java開發中&#xff0c;垃圾收集器的選擇對系統性能有著致命的影響。Java 8后&#xff0c;雖然G1 GC成為默認&#xff0c;但是它在延遲性控制上仍有限。ZGC作為最新一代高性能低延遲垃圾收集器&#xff0c;解決了CMS和G1在延遲、垃圾堆容量和吞吐量方面的重大突破。本文將…