Spring Boot 應用優雅關閉

寫這篇文章是因為看到 “線程池在使用結束后應該正確關閉.” 那么如果我們的 Spring 應用都無法正確關閉, 那么線程池肯定也無從保障

1. 優雅關閉

  • kill with pid, without -9

大多數情況下無須在意這個問題, 正確使用 kill 命令關閉就行 (注意不能使用 kill -9)

kill $(cat ./application.pid)

默認發送的信號是 SIGTERM,其信號編號為 15. 在無法正常終止進程時使用 -9 (SIGKILL): 強制立即終止進程。這個信號無法被捕獲或忽略,進程會被操作系統強制殺死

  • 在啟動的時候, 將 pid 和 端口號 記錄到文件中 (這些文件在程序關閉后會自動刪除)
public static void main(String[] args) {try {long start = System.currentTimeMillis();SpringApplicationBuilder builder = new SpringApplicationBuilder(App.class);builder.beanNameGenerator(FullyQualifiedAnnotationBeanNameGenerator.INSTANCE);// startup with pid file and port filebuilder.listeners(new ApplicationPidFileWriter()); // pid file// 上面的類可以傳入文件路徑, 方便使用 kill 命令// builder.listeners(new ApplicationPidFileWriter("./bin/shutdown.pid")); // kill $(cat ./bin/shutdown.pid)builder.listeners(new WebServerPortFileWriter()); // port filebuilder.run(args);long costs = (System.currentTimeMillis() - start) / 1000;log.info("### APP STARTED ### It take {} seconds.", costs);} catch (Exception e) { log.error(" STARTUP FAILED ", e); }
}

2. 增加 URL 接口來關閉程序

  1. 使用 ConfigurableApplicationContext#close
  2. 使用 int exit = SpringApplication.exit(context);
  3. 關閉應用時執行某段邏輯
    1. 注解 @PreDestroy
    2. 事件 ContextClosedEvent
@Slf4j
@RestController
public class ShutDownController {@Autowiredprivate ConfigurableApplicationContext applicationContext;@Autowiredprivate ApplicationContext context; // 兩個 context 都行@GetMapping("/shutdown")public String shutdown() {log.error("1. shutdown begin..."); // 前面的編號是執行順序// 清理資源并關閉((ConfigurableApplicationContext) context).close();// applicationContext.close();log.error("3. spring application closed.");// 在嵌入式應用或在某些情況下,關閉上下文后,JVM 可能不會自動退出。為了確保應用完全終止,使用 System.exit(0)System.exit(0); // not necessary// log.error("system closed."); // 這里日志對象 log 已經失效, 無法打印, 換用 printlnSystem.err.println("system closed.");return "shutdown";}@GetMapping("/exit")public String exit() {log.error("1. shutdown begin...");// 負責清理資源int exit = SpringApplication.exit(context);log.error("3. Spring app closed.");System.exit(exit); // not necessary// log.error("system closed."); // It will fail overSystem.err.println("system closed.");return "shutdown";}@PreDestroy // @PreDestroy 注解: 在 Spring 應用銷毀前, 執行某段邏輯public void onDestroy() throws Exception {log.error("3. Spring Container is destroyed!");}@Slf4j@Component // ContextClosedEvent 事件: 在 Spring 上下文關閉時機, 執行某段邏輯public // public 不是必須static // @Slf4j is not supported on non-static nested classes.class ApplicationShutdown implements ApplicationListener<ContextClosedEvent> {@Overridepublic void onApplicationEvent(ContextClosedEvent event) {log.error("2. graceful shutdown (ContextClosedEvent)");}}
}

Spring 并沒有強制要求內部類必須是 publicstatic。但在最佳實踐中:

  1. 使用 static 內部類可以避免使用處有不必要的引用,特別是當內部類不需要訪問外部類的實例時。
  2. public 不是必須: 如果內部類不需要在外部訪問,它可以是 package-private(默認)或 protected。通常建議將其定義為 publicstatic,以提高可維護性。

3. 優雅啟動

  1. 顯示配置參數
    /*** 顯示配置參數*/public static void printEnvironment(Environment environment) {try {log.info("******************JVM參數**********************");String[] properties = {"java.home", "java.version", "java.vm.name", "java.vm.vendor", "os.name", "user.dir"};for (String property : properties) {log.info("* {} = {}", property, System.getProperty(property));}MemoryMXBean bean = ManagementFactory.getMemoryMXBean();MemoryUsage heapUsage = bean.getHeapMemoryUsage();log.info("* 初始內存 = " + heapUsage.getInit() / 1024 / 1024 + "M");log.info("* 已使用內存 = " + heapUsage.getUsed() / 1024 / 1024 + "M");log.info("* 已提交內存 = " + heapUsage.getCommitted() / 1024 / 1024 + "M");log.info("* 最大內存 = " + heapUsage.getMax() / 1024 / 1024 + "M");} catch (Exception e) {log.error("異常: {}", e.getMessage());}}
  1. 啟動時調用: printEnvironment(builder.context().getEnvironment());

4. 線程池的關閉

  1. 由 Spring 管理的線程池, 關閉 Spring 應用上下文時會自動關閉, 包括 @Async 或 通過 Spring 配置的線程池

  2. 自定義線程池 (未通過 Spring 管理), 在關閉應用時, 需要顯式地調用 shutdown() 來確保任務能夠正常完成, 避免丟失. 可以利用上面提到的, 關閉應用時執行某段邏輯的方式執行

    1. 注解 @PreDestroy
    2. 事件 ContextClosedEvent

(END)

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

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

相關文章

linux與c語言基礎知識(未全部完成)

文章很多處理論&#xff0c;沒辦法寫出來&#xff0c;&#xff08;linux的一些理論問題&#xff0c;我有時間后&#xff0c;會逐個解決&#xff09; 文章大多數的理論來字這個鏈接&#xff0c; C語言快速入門-C語言基礎知識-CSDN博客 一. linux&#xff08;Ubuntu&#xff09; …

面試經歷(一)雪花算法

uid生成方面 1&#xff1a;為什么用雪花算法 分布式ID的唯一性需要保證&#xff0c;同時需要做到 1&#xff1a;單調遞增 2&#xff1a;確保安全&#xff0c;一個是要能體現出遞增的單號&#xff0c;二一個不能輕易的被惡意爬出訂單數量 3&#xff1a;含有時間戳 4&#…

基于GA遺傳優化TCN-BiGRU注意力機制網絡模型的時間序列預測算法matlab仿真

目錄 1.算法運行效果圖預覽 2.算法運行軟件版本 3.部分核心程序 4.算法理論概述 5.算法完整程序工程 1.算法運行效果圖預覽 (完整程序運行后無水印) 2.算法運行軟件版本 matlab2024b&#xff08;提供軟件版本下載&#xff09; 3.部分核心程序 &#xff08;完整版代碼包…

深度強化學習 pdf 董豪| 馬爾科夫性質,馬爾科夫過程,馬爾科夫獎勵過程,馬爾科夫決策過程

深度強化學習 pdf 百度云 hea4 pdf 主頁 概念 馬爾可夫獎勵過程和價值函數估計的結合產生了在絕大多數強化學習方法中應用的核心結果——貝爾曼 &#xff08;Bellman&#xff09;方程。最優價值函數和最優策略可以通過求解貝爾曼方程得到&#xff0c;還將介紹三種貝爾曼 方…

驗證Kubernetes的服務發現機制

驗證Kubernetes的服務發現機制 文章目錄 驗證Kubernetes的服務發現機制[toc]一、驗證基于環境變量的服務發現機制 服務發現是讓客戶端能夠以固定的方式獲取到后端Pod訪問地址的機制。下面驗證環境變量和DNS這兩種機制。 一、驗證基于環境變量的服務發現機制 對于需要訪問服務…

FPGA系列之DDS信號發生器設計(DE2-115開發板)

一、IP核 IP(Intellectual Property)原指知識產權、著作權等&#xff0c;在IC設計領域通常被理解為實現某種功能的設計。IP模塊則是完成某種比較復雜算法或功能&#xff08;如FIR濾波器、FFT、SDRAM控制器、PCIe接口、CPU核等&#xff09;并且參數可修改的電路模塊&#xff0c…

Java單例模式詳解:實現線程安全的全局訪問點

精心整理了最新的面試資料和簡歷模板&#xff0c;有需要的可以自行獲取 點擊前往百度網盤獲取 點擊前往夸克網盤獲取 一、什么是單例模式&#xff1f; 單例模式&#xff08;Singleton Pattern&#xff09;是一種創建型設計模式&#xff0c;它保證一個類僅有一個實例&#xff…

JVM 生產環境問題定位與解決實戰(七):實戰篇——OSSClient泄漏引發的FullGC風暴

本文已收錄于《JVM生產環境問題定位與解決實戰》專欄&#xff0c;完整系列見文末目錄 引言 在前六篇博客中&#xff0c;我們系統性地學習了 JVM 生產環境問題定位與解決的全套工具鏈&#xff0c;涵蓋jps、jmap、jstat、jstack、jcmd 等基礎工具的使用技巧&#xff0c;深入剖析…

Spark集群搭建-spark-local

&#xff08;一&#xff09;安裝Spark 安裝Spark的過程就是下載和解壓的過程。接下來的操作&#xff0c;我們把它上傳到集群中的節點&#xff0c;并解壓運行。 1.啟動虛擬機 2.通過finalshell連接虛擬機&#xff0c;并上傳安裝文件到 /opt/software下 3.解壓spark安裝文件到/op…

Java 異常 SSLException: fatal alert: protocol_version 全解析與解決方案

在 Java 網絡通信中&#xff0c;SSLException: fatal alert: protocol_version 是典型的 TLS/SSL 協議版本不兼容異常。本文結合 Java 官方規范、TLS 協議標準及實戰經驗&#xff0c;提供體系化解決方案&#xff0c;幫助開發者快速定位并解決協議版本沖突問題。 一、異常本質&…

虛擬列表技術深度解析:原理、實現與性能優化實戰

虛擬列表技術深度解析&#xff1a;原理、實現與性能優化實戰 引言 在當今數據驅動的互聯網應用中&#xff0c;長列表渲染已成為前端開發的核心挑戰。傳統的一次性全量渲染方式在數據量超過千條時&#xff0c;往往導致頁面卡頓、內存飆升等問題。虛擬列表&#xff08;Virtual L…

2025-04-20 李沐深度學習4 —— 自動求導

文章目錄 1 導數拓展1.1 標量導數1.2 梯度&#xff1a;向量的導數1.3 擴展到矩陣1.4 鏈式法則 2 自動求導2.1 計算圖2.2 正向模式2.3 反向模式 3 實戰&#xff1a;自動求導3.1 簡單示例3.2 非標量的反向傳播3.3 分離計算3.4 Python 控制流 硬件配置&#xff1a; Windows 11Inte…

Redis的使用總結

Redis 核心使用場景 緩存加速 高頻訪問數據緩存&#xff08;如商品信息、用戶信息&#xff09; 緩解數據庫壓力&#xff0c;提升響應速度 會話存儲 分布式系統共享 Session&#xff08;替代 Tomcat Session&#xff09; 支持 TTL 自動過期 排行榜/計數器 實時排序&#x…

富文本編輯器實現

&#x1f3a8; 富文本編輯器實現原理全解析 &#x1f4dd; 基本實現路徑圖 #mermaid-svg-MO1B8a6kAOmD8B6Y {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MO1B8a6kAOmD8B6Y .error-icon{fill:#552222;}#mermaid-s…

LeetCode熱題100——283. 移動零

給定一個數組 nums&#xff0c;編寫一個函數將所有 0 移動到數組的末尾&#xff0c;同時保持非零元素的相對順序。 請注意 &#xff0c;必須在不復制數組的情況下原地對數組進行操作。 示例 1: 輸入: nums [0,1,0,3,12] 輸出: [1,3,12,0,0] 示例 2: 輸入: nums [0] 輸出:…

與Ubuntu相關命令

windows將文件傳輸到Ubuntu 傳輸文件夾或文件 scp -r 本地文件夾或文件 ubuntu用戶名IP地址:要傳輸到的文件夾路徑 例如&#xff1a; scp -r .\04.py gao192.168.248.129:/home/gao 如果傳輸文件也可以去掉-r 安裝軟件 sudo apt-get update 更新軟件包列表 sudo apt insta…

Kafka 在小流量和大流量場景下的順序消費問題

一、低流量系統 特點 消息量較少&#xff0c;吞吐量要求低。系統資源&#xff08;如 CPU、內存、網絡&#xff09;相對充足。對延遲容忍度較高。 保證順序消費的方案 單分區 單消費者 將消息發送到單個分區&#xff08;例如固定 Partition 0&#xff09;&#xff0c;由單個…

小程序 GET 接口兩種傳值方式

前言 一般 GET 接口只有兩種URL 參數和路徑參數 一&#xff1a;URL 參數&#xff08;推薦方式&#xff09; 你希望請求&#xff1a; https://serve.zimeinew.com/wx/products/info?id5124接口應該寫成這樣&#xff0c;用 req.query.id 取 ?id5124&#xff1a; app.get(&…

小白學習java第14天(中):數據庫

1.DML data manage language數據庫管理語言 外鍵:外鍵是什么&#xff1f;就是對其進行表與表之間的聯系&#xff0c;就是使用的鍵進行關聯&#xff01; 方法一&#xff1a;我們在數據庫里面就對其進行表與表之間的連接【這種是不建議的&#xff0c;我不太喜歡就是將數據里面弄…

NO.95十六屆藍橋杯備戰|圖論基礎-單源最短路|負環|BF判斷負環|SPFA判斷負環|郵遞員送信|采購特價產品|拉近距離|最短路計數(C++)

P3385 【模板】負環 - 洛谷 如果圖中存在負環&#xff0c;那么有可能不存在最短路。 BF算法判斷負環 執?n輪松弛操作&#xff0c;如果第n輪還存在松弛操作&#xff0c;那么就有負環。 #include <bits/stdc.h> using namespace std;const int N 2e3 10, M 3e3 1…