駕馭 Spring Boot 事件機制:8 個內置事件 + 自定義擴展實戰

駕馭 Spring Boot 事件機制:8 個內置事件 + 自定義擴展實戰

在 Spring Boot 應用的完整生命周期中,框架為我們預埋了 8 個關鍵事件(Application-level & Context-level)。 理解并善用這些事件,可以在“不侵入框架、不修改源碼”的前提下,注入個性化初始化、監控、清理邏輯。 本文將帶你從 0 到 1 掌握事件機制,并給出可直接落地的代碼模板。


一、為什么需要事件機制?

場景傳統做法事件機制優勢
啟動時加載字典緩存CommandLineRunner無侵入、可插拔、可排序
優雅停機@PreDestroy與 Spring 生命周期同步,確保資源釋放順序
多模塊解耦直接調用發布-訂閱,模塊間零依賴

二、Spring Boot 8 大內置事件一覽

事件觸發階段典型用途監聽器注冊方式
ApplicationStartingEventrun() 剛被調用,日志系統尚未初始化極早期檢查、初始化日志橋接SpringApplication.addListeners(...)
ApplicationEnvironmentPreparedEventEnvironment 已就緒,但 BeanDefinition 尚未加載動態修改配置源、激活 Profile同上
ApplicationContextInitializedEventApplicationContext 已創建,但尚未 refresh注冊 BeanFactoryPostProcessor同上
ApplicationPreparedEventBeanDefinition 已加載,Environment 可用讀取配置、校驗必備屬性同上
ContextRefreshedEventrefresh() 完成,所有單例已實例化緩存預熱、注冊監控@Component
ServletWebServerInitializedEvent內嵌容器端口已打開獲取運行時端口、注冊服務發現@Component
ApplicationStartedEvent容器已啟動,所有 CommandLineRunner 已執行發送啟動成功指標@Component
ApplicationReadyEvent同上,額外保證所有應用初始化器已完成開啟流量、發送通知@Component

Spring Boot 2.x 之后新增 ApplicationStartingEventApplicationStartedEvent 等,舊版只有 5 個核心事件。


三、實戰:監聽 4 個高頻事件

1. 啟動早期動態注入配置

public class EarlyEnvInjector implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {@Overridepublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {ConfigurableEnvironment env = event.getEnvironment();// 模擬從 Apollo/Nacos 拉取最新配置Map<String, Object> override = Map.of("spring.datasource.url", "jdbc:mysql://newHost/dev");env.getPropertySources().addFirst(new MapPropertySource("dynamic", override));}
}

注冊方式(在 main 方法里):

SpringApplication app = new SpringApplication(DemoApp.class);
app.addListeners(new EarlyEnvInjector());
app.run(args);

2. 容器刷新后預熱緩存

@Component
public class CacheWarmer implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if (event.getApplicationContext().getParent() == null) { // 防止重復執行DictCache.loadAll();}}
}

3. 優雅停機前釋放資源

@Component
public class GracefulShutdown implements ApplicationListener<ContextClosedEvent> {private final ExecutorService pool = Executors.newFixedThreadPool(10);@Overridepublic void onApplicationEvent(ContextClosedEvent event) {pool.shutdown();try {if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {pool.shutdownNow();}} catch (InterruptedException e) {pool.shutdownNow();}}
}

4. 啟動完畢發送監控告警

@Component
public class StartupReporter implements ApplicationListener<ApplicationReadyEvent> {@Overridepublic void onApplicationEvent(ApplicationReadyEvent event) {InetAddress host = InetAddress.getLocalHost();String port = event.getApplicationContext().getEnvironment().getProperty("local.server.port");DingTalk.send("? 服務啟動完成: " + host.getHostAddress() + ":" + port);}
}

四、擴展:自定義業務事件

1. 定義領域事件

public class OrderPaidEvent extends ApplicationEvent {private final Long orderId;private final BigDecimal amount;public OrderPaidEvent(Object source, Long orderId, BigDecimal amount) {super(source);this.orderId = orderId;this.amount = amount;}// getters ...
}

2. 發布事件

@Service
@RequiredArgsConstructor
public class OrderService {private final ApplicationEventPublisher publisher;public void pay(Long orderId) {// 業務邏輯...publisher.publishEvent(new OrderPaidEvent(this, orderId, BigDecimal.valueOf(99)));}
}

3. 多監聽器異步消費

@Component
public class InvoiceGenerator {@EventListener@Async("invoiceTaskExecutor")   // 線程池隔離public void onOrderPaid(OrderPaidEvent event) {// 生成電子發票...}
}

五、最佳實踐清單

  1. 順序控制:使用 @Order 或實現 Ordered 接口。
  2. 線程安全:早期事件(如 ApplicationStartingEvent)發布時,Bean 尚未實例化,此時注冊邏輯需避免依賴 IOC 容器。
  3. 條件化監聽@ConditionalOnPropertyEnvironment 判斷,避免在測試環境觸發線上邏輯。
  4. 異步場景@Async + 自定義線程池,防止阻塞主流程。
  5. 可觀測性:通過 Micrometer 記錄事件處理耗時,及時發現慢監聽器。

六、小結

目標推薦事件
動態修改配置ApplicationEnvironmentPreparedEvent
容器初始化后一次性任務ContextRefreshedEvent
優雅停機ContextClosedEvent
服務啟動成功通知ApplicationReadyEvent
業務解耦自定義 ApplicationEvent

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

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

相關文章

【kafka4源碼學習系列】kafka4總體架構介紹

二 kafka架構介紹學習一個系統之前很重要的一點就是先了解這個系統整體的架構&#xff0c;這能夠使我們對整個系統有個總體的認識&#xff0c;清楚地知道這個系統有什么能力。這不僅幫助我們學習時快速定位到我們想要的內容&#xff0c;還能避免我們學習過程中在龐大的系統中迷…

java內存圖

java內存圖java文件運行流程程序的內存空間認識虛擬機棧程序的執行流程認識堆java的類與對象的關系java文件運行流程 有這樣的一份 java 文件 在該目錄下的終端運行 javac Hello.java 命令&#xff0c;會生成 Hello.class 文件&#xff0c;內容如下&#xff1a; Hello.java 打…

vscode編輯Markdown文件

一.安裝Markdown的插件 vscode的擴展&#xff0c;搜索Markdown Preview Enhanced的插件&#xff0c;并安裝。 其他的常用插件&#xff0c;還包括&#xff1a; Markdown All in One &#xff1a;提供了許多有用的功能&#xff0c;如快捷鍵支持、自動預覽、TOC&#xff08;目錄&…

【PTA數據結構 | C語言版】查找樹中帶有指定數據的結點

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 請編寫程序&#xff0c;創建有 4 個結點的樹&#xff0c;然后查找給定的 x。 輸入格式&#xff1a; 輸入首先在第一行給出 4 個正整數&#xff0c;依次對應樹的根結點、根的第 1、2、3 個孩子結點的…

PostgreSQL常用命令與工具指南

文章目錄PostgreSQL常用命令與工具指南簡介1. 連接與基本操作連接數據庫環境變量設置&#xff08;避免密碼輸入&#xff09;常用元命令2. 數據庫與表管理數據庫操作創建數據庫刪除數據庫修改數據庫屬性表操作創建表修改表結構刪除表索引管理創建索引刪除索引3. 數據操作(CRUD)插…

SpringBoot項目部署至云服務器

目錄 一、后端項目部署 1、修改配置文件 2、清理打包緩存&#xff0c;打jar包&#xff08;兩種方式二選一&#xff09; 自動打包 手動打包 打包成功狀態 3、將jar包導入宿主機上 jar包位置 jar包上傳 jar包運行 瀏覽器測試 二、前端代碼 docker搭建nginx的基本步驟 打…

Agent-S:重新定義下一代 AI 智能體開發框架

Agent-S&#xff1a;重新定義下一代 AI 智能體開發框架 —— 探索 simular-ai 的開源革命 引言 2025 年&#xff0c;AI 智能體&#xff08;Agent&#xff09;技術正從概念走向產業核心。從自動化工作流到復雜決策系統&#xff0c;開發者亟需更高效的工具鏈。在這一背景下&am…

保持視頻二維碼不變,如何更新視頻內容,節省物料印刷成本

保持視頻二維碼不變&#xff0c;如何更新視頻內容&#xff0c;節省物料印刷成本&#xff1f; 視頻替換功能&#xff0c;是指在保持視頻二維碼不變、視頻觀看地址不變、視頻調用代碼不變的情況下替換視頻內容&#xff0c;從而節省用戶印刷物料的成本&#xff0c;滿足用戶更新視…

flutter項目調試問題小結

背景 目標是用android studio flutter 跑hello world 下載 android studio 我下載的是2024.3.2.15版本 最新版下載首頁就能下&#xff1a;下載 Android Studio 和應用工具 - Android 開發者 | Android Developers 歷史版本可在歸檔列表下載&#xff1a;Android Studio…

明細列表,明細grid中的默認按鈕失效,配置按鈕失效

明細列表&#xff0c;明細grid中的默認按鈕失效&#xff0c;配置按鈕失效原因&#xff1a;采用通配的寫法導致的默認按鈕失效if(menuDetails){menuDetails.forEach((item) > {const { name, menu_detail_columns, menu_detail_buttons, save_url} item;this.set(${name}Gri…

Matplotlib 30分鐘精通

?? Matplotlib 30分鐘精通計劃(完整版含輸出) ? 時間分配 5分鐘:Matplotlib基礎概念和簡單圖表 10分鐘:常用圖表類型詳解 10分鐘:圖表美化和定制 5分鐘:綜合實戰練習 ?? 第一部分:Matplotlib基礎概念 (5分鐘) 1. 什么是Matplotlib? import matplotlib.pyplot a…

7月19日 暴雨藍色預警:全國多地迎強降雨,需防范次生災害

中央氣象臺7月19日10時繼續發布暴雨藍色預警,預計未來24小時(19日14時至20日14時),我國多地將迎來大到暴雨,局地甚至出現大暴雨,并伴有短時強降水、雷暴大風等強對流天氣,需加強防范。 強降雨覆蓋范圍廣,多地需警惕極端降水 此次降雨影響范圍廣泛,涉及華北、華南、西…

Redis學習-05Redis基本數據結構

Redis 數據結構 String 字符串 基本命令表命令執行效果時間復雜度set key value [key value…]設置 key 的值是 valueO(k), k 是鍵個數get key獲取 key 的值O(1)del key [key …]刪除指定的 keyO(k), k 是鍵個數mset key value [key value …]批量設置指定的 key 和 valueO(k),…

開啟modbus tcp模擬調試

1、新建modbus tcp服務器 ?功能差異??客戶端功能?&#xff1a; 生成并發送Modbus請求報文&#xff08;如功能碼03讀取寄存器&#xff09;。?? 解析服務器響應數據&#xff0c;實現遠程監控或控制。?? ?服務器端功能?&#xff1a; 監聽默認端口&#xff08;如502&…

昇思+香橙派 AI 開發實踐:DeepSeek 全流程指南(基于 openEuler)

一、 環境準備 1. 鏡像燒錄 鏡像燒錄可以在任何操作系統內執?&#xff0c;這?以在Windows系統為例&#xff0c;使用balenaEtcher?具&#xff0c;快速燒錄鏡像到Micro SD卡中。 本章節所需的軟/硬件如下&#xff1a; 軟件相關&#xff1a;balenaEtcher制卡?具、openEul…

AI生成郵件發送腳本(帶附件/HTML排版)與定時爬取網站→郵件通知(價格監控原型)

想象一下&#xff1a;每天早晨咖啡還沒喝完&#xff0c;你的郵箱就自動收到了心儀商品的最新價格&#xff1b;重要報告準時帶著專業排版的附件發送到客戶手中——這一切不需要你手動操作。本文將用不到100行代碼帶你實現這兩個自動化神器&#xff01; 一、為什么我們需要自動化…

【vLLM 學習】Encoder Decoder Multimodal

vLLM 是一款專為大語言模型推理加速而設計的框架&#xff0c;實現了 KV 緩存內存幾乎零浪費&#xff0c;解決了內存管理瓶頸問題。 更多 vLLM 中文文檔及教程可訪問 →https://vllm.hyper.ai/ *在線運行 vLLM 入門教程&#xff1a;零基礎分步指南 源碼 examples/offline_inf…

【MySQL筆記】視圖

目錄一、什么是視圖&#xff1f;二、使用視圖的優勢三、視圖的創建與使用四、不能更新視圖的場景五、刪除視圖六、總結一、什么是視圖&#xff1f; 視圖&#xff08;View&#xff09;是一種虛擬表&#xff0c;不存儲實際數據&#xff0c;而是通過執行預定義的查詢動態生成數據…

【RK3576】【Android14】分區劃分

獲取更多相關的【RK3576】【Android14】驅動開發&#xff0c;可收藏系列博文&#xff0c;持續更新中&#xff1a; 【RK3576】Android 14 驅動開發實戰指南

Datawhale 25年7月組隊學習coze-ai-assistant Task1學習筆記:動手實踐第一個AI Agent—英倫生活口語陪練精靈

Chap1 了解AI工作流 1.1什么是工作流 工作流 就像是一條流水線&#xff0c;把復雜的任務拆分成多個簡單的步驟&#xff0c;每一步都有明確的目標和流程。1.2智能體和工作流的區別 智能體&#xff08;AI Agent&#xff09; **是什么 &#xff1a;**智能體是一個自動化的“助手”…