Spring監聽器

1、監聽器的原理

ApplicationListener<T>是Spring框架中基于觀察者模式實現的事件監聽接口,用于監聽應用程序中特定類型的事件。該接口是一個函數式接口,從Spring 4.2開始支持Lambda表達式實現。

接口定義如下:

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);
}

核心特性包括:

  • ?泛型參數T?:限定監聽的事件類型,必須是ApplicationEvent的子類。
  • ?函數式接口?:支持Lambda表達式簡化實現。
  • ?事件過濾?:只會接收到指定類型的事件通知。
  • ?觀察者模式?:實現發布-訂閱機制,解耦事件生產者和消費者?。

監聽器的原理:

  1. 事件發布者調用publishEvent()方法發布事件。
  2. ApplicationEventMulticaster獲取所有匹配的監聽器。
  3. 通過反射調用監聽器的onApplicationEvent()方法。
  4. 監聽器處理完成后返回,流程結束。

ApplicationEventMulticaster?是事件廣播器,負責管理監聽器和事件分發?。

下面是一段自定義監聽器的代碼,包括自定義事件、發布事件和監聽事件。

自定義事件CustomEvent.java:

package com.example.event;import org.springframework.context.ApplicationEvent;public class CustomEvent extends ApplicationEvent {private String data;public CustomEvent(Object source, String data) {super(source);this.data = data;}public String getData() {return data;}
}

EventPublisher類負責發布事件,真正觸發事件發布是在具體業務代碼中。

package com.example.event;import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;@Component
public class EventPublisher {private final ApplicationContext context;public EventPublisher(ApplicationContext context) {this.context = context;}public void publish(String data) {context.publishEvent(new CustomEvent(this, data));}
}

OrderService在業務處理完成后發布事件:

package com.example.service;import com.example.event.EventPublisher;
import org.springframework.stereotype.Service;@Service
public class OrderService {private final EventPublisher eventPublisher;public OrderService(EventPublisher eventPublisher) {this.eventPublisher = eventPublisher;}public void createOrder(String orderId) {// 業務處理...eventPublisher.publish("Order created: " + orderId);}
}

自定義監聽器OrderEventListener處理監聽事件:

package com.example.listener;import com.example.event.CustomEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class OrderEventListener implements ApplicationListener<CustomEvent> {@Overridepublic void onApplicationEvent(CustomEvent event) {System.out.println("收到訂單事件: " + event.getData());// 處理邏輯:發送通知、更新狀態等}
}

@EventListener 是Spring 4.2引入的基于注解的聲明式監聽方式?,實現與ApplicationListener接口相同的功能,并且更加靈活。建議優先使用@EventListener注解的方式實現監聽器,對于遺留系統需要保持與舊版本代碼風格一致?的可以使用ApplicationListener。

@Component
public class MyPreListener {@EventListenerpublic void handleRequestStart(ServletRequestEvent event) {System.out.println("請求開始之前進行預處理操作: " + event.getServletRequest());}@EventListenerpublic void handleRequestCompletion(ServletRequestHandledEvent event) {System.out.println("響應返回之前進行后置處理操作");}
}

2、監聽事件類型

Spring提供了豐富的事件類型,都是ApplicationEvent的子類,主要分為以下幾類:

1. 容器生命周期事件

  • ?ContextRefreshedEvent?:容器刷新或初始化完成之后觸發
  • ?ContextStartedEvent?:容器調用start()方法啟動時觸發。
  • ?ContextStoppedEvent?:容器調用stop()方法后觸發。
  • ?ContextClosedEvent?:容器關閉時觸發?。

2. Spring Boot特有事件

  • ?ApplicationStartingEvent?:應用啟動但未做任何初始化時觸發?。
  • ?ApplicationEnvironmentPreparedEvent?:環境準備就緒但上下文未創建。
  • ?ApplicationPreparedEvent?:容器刷新前觸發?。
  • ?ApplicationReadyEvent?:應用完全就緒可接收請求
  • ?ApplicationFailedEvent?:啟動失敗時觸發。

3. Web相關事件

  • ?ServletRequestEvent:請求開始時做一些預處理操作。
  • ServletRequestHandledEvent?:請求結束返回響應之前做一些后置處理操作。?
  • ?RequestHandledEvent?:請求處理完成后觸發(比ServletRequestHandledEvent更通用)。
  • HttpSessionCreatedEvent:會話創建時觸發,用于會話管理。
  • HttpSessionDestroyedEvent:會話銷毀時觸發,用于資源清理。

例如請求接口時可以通過?ServletRequestEvent事件做一些預處理操作,或者返回響應之前通過ServletRequestHandledEvent?事件做一些后置操作。

@Component
public class PreRequestListener implements ApplicationListener<ServletRequestEvent> {@Overridepublic void onApplicationEvent(ServletRequestEvent event) {// 請求預處理邏輯}
}@Component
public class PostRequestListener implements ApplicationListener<ServletRequestHandledEvent> {@Overridepublic void onApplicationEvent(ServletRequestHandledEvent event) {// 請求后處理邏輯}
}

下面重點看一下?ContextRefreshedEvent?和ApplicationReadyEvent事件。

根據Spring bean的初始化-CSDN博客這篇文章可知,常用的spring bean的初始化方法有以下四種:

(1)@PostConstruct注解的方法;

(2)類實現了InitializingBean接口,實現了afterPropertiesSet方法;

(3)通過XML配置文件在<bean>標簽中的init-method屬性指定初始化方法,或者@Bean的initMethod屬性指定的方法,如@Bean(initMethod = "init"),其中init是一個方法;

(4)還可以自定義后置處理器實現BeanPostProcessor接口,重寫postProcessBeforeInitialization方法實現初始化。

以上這四種初始化方法如果在一個類上同時使用,執行順序是(4)>(1)>(2)>(3)。

ContextRefreshedEvent?事件是在Spring容器完成初始化之后觸發的,它主要用于執行需要在所有Bean就緒后才能進行的全局操作,如緩存預熱、數據預加載等。?ContextRefreshedEvent?是Spring框架原生事件,表示Spring容器ApplicationContext已初始化或刷新完成?。在Spring Boot中,?ContextRefreshedEvent?位于ApplicationPreparedEvent之后和ApplicationStartedEvent之前,更在ApplicationReadyEvent之前?。

ApplicationReadyEvent具有與?ContextRefreshedEvent?相似的功能,也可以執行緩存預熱、數據預加載的操作。ApplicationReadyEvent是Spring Boot特有事件,表示應用程序已完全啟動并準備好接收請求?,是整個啟動過程中最后觸發的事件,確保所有基礎設施就緒?。ApplicationReadyEvent事件在ApplicationRunner與CommandLineRunner執行完成后?執行。

ContextRefreshedEvent?與ApplicationReadyEvent功能特性對比:

特性

ContextRefreshedEvent

ApplicationReadyEvent

所屬框架

Spring原生

Spring Boot特有

觸發確定性

可能多次觸發(父子容器)

確保只觸發一次

基礎設施狀態

容器就緒,外部服務未保證

所有基礎設施(如Web服務器)已就緒

適用階段

容器初始化后

應用完全可用時

健康檢查

未執行

已通過?

應用場景分析:

1. ContextRefreshedEvent適用場景

  • ?Bean初始化后的配置調整?:當需要基于已初始化的Bean進行動態配置時。
  • ?內部緩存預熱?:加載不依賴外部服務的內部緩存數據。
  • ?早期資源初始化?:需要在容器就緒后立即執行的輕量級操作。
  • ?多模塊系統中的模塊間協調?:在復雜應用中協調不同模塊的初始化順序。

2. ApplicationReadyEvent適用場景

  • ?外部服務連接?:建立與數據庫、消息隊列等外部服務的連接。
  • ?定時任務啟動?:確保所有依賴Bean就緒后再啟動定時任務。
  • ?服務注冊?:向服務注冊中心(如Eureka)注冊服務實例。
  • ?就緒狀態通知?:通知監控系統應用已準備好接收流量。
  • ?關鍵資源檢查?:驗證所有必要服務是否正常啟動。

實際工作中的選擇建議:

純Spring應用?:只能使用ContextRefreshedEvent?。

Spring Boot應用?:

  • 需要確保基礎設施就緒 → 選擇ApplicationReadyEvent?。
  • 僅需容器初始化后操作 → 選擇ContextRefreshedEvent?。
  • 微服務架構中的服務注冊 → 必須使用ApplicationReadyEvent?。

ContextRefreshedEvent中應檢查event.getApplicationContext().getParent()避免重復執行?,ApplicationReadyEvent天然保證單次執行?。ContextRefreshedEvent中的異常可能阻止應用啟動?,ApplicationReadyEvent中的異常通常不會阻止啟動但應記錄?。在springboot項目中,如果需要在Spring容器初始化之后,且正式對外提供服務之前做一些預處理操作,盡量使用ApplicationReadyEvent?。

ContextRefreshedEvent事件監聽的代碼示例:

@Component
public class MyContextListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 避免在Web環境中因父子容器重復執行if (event.getApplicationContext().getParent() == null) {// 執行容器初始化后的操作System.out.println("Context refreshed, beans are ready");}}
}

ApplicationReadyEvent事件監聽的代碼示例:

@Component
public class MyAppReadyListener {@EventListenerpublic void onApplicationReady(ApplicationReadyEvent event) {// 應用完全就緒后可安全執行的操作System.out.println("Application is fully ready to serve requests");// 示例:啟動定時任務ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);scheduler.scheduleAtFixedRate(() -> System.out.println("Periodic task running"), 0, 1, TimeUnit.MINUTES);}
}

通過過濾器和攔截器實現請求前和請求后進行處理操作:

Filter實現請求前后處理:

@Component
public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("請求前處理");chain.doFilter(request, response);System.out.println("請求后處理");}
}

Interceptor實現請求前后處理:

@Component
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("請求前處理");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("請求后處理");}
}

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

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

相關文章

基于Rust游戲引擎實踐(Game)

Rust游戲引擎推薦 以下是一些流行的Rust游戲引擎,適用于不同開發需求: Bevy 特點:數據驅動、模塊化設計,支持ECS架構,適合初學者和復雜項目。 適用場景:2D/3D游戲、原型開發。 Amethyst 特點:成熟的ECS框架,支持多線程,社區活躍。 適用場景:大型游戲或高性能應用。…

PyTorch 數據加載實戰:從 CSV 到圖像的全流程解析

目錄 一、PyTorch 數據加載的核心組件 1.1 Dataset 類的核心方法 1.2 DataLoader 的作用 二、加載 CSV 數據實戰 2.1 自定義 CSV 數據集 2.2 使用 TensorDataset 快速加載 三、加載圖像數據實戰 3.1 自定義圖像數據集 3.2 使用 ImageFolder 快速加載 四、加載官方數據…

程序人生,開啟2025下半年

時光匆匆&#xff0c;2025年已然過去一半。轉眼來到了7月份。 回望過去上半年&#xff0c;可能你也經歷了職場的浮沉、生活的跌宕、家庭的變故。 而下半年&#xff0c;生活依舊充滿了各種變數。 大環境的起起伏伏、生活節奏的加快&#xff0c;都讓未來的不確定性愈發凸顯。 在這…

在 .NET Core 中創建 Web Socket API

要在 ASP.NET Core 中創建 WebSocket API&#xff0c;您可以按照以下步驟操作&#xff1a;設置新的 ASP.NET Core 項目打開 Visual Studio 或您喜歡的 IDE。 創建一個新的 ASP.NET Core Web 應用程序項目。 選擇API模板&#xff0c;因為這將成為您的 WebSocket API 的基礎。在啟…

Python 之地址編碼識別

根據輸入地址&#xff0c;利用已有的地址編碼文件&#xff0c;構造處理規則策略識別地址的編碼。 lib/address.json 地址編碼文件&#xff08;這個文件太大&#xff0c;博客里放不下&#xff0c;需要的話可以到 gitcode 倉庫獲取&#xff1a;https://gitcode.com/TomorrowAndT…

kafka的部署

目錄 一、kafka簡介 1.1、概述 1.2、消息系統介紹 1.3、點對點消息傳遞模式 1.4、發布-訂閱消息傳遞模式 二、kafka術語解釋 2.1、結構概述 2.2、broker 2.3、topic 2.4、producer 2.5、consumer 2.6、consumer group 2.7、leader 2.8、follower 2.9、partition…

小語種OCR識別技術實現原理

小語種OCR&#xff08;光學字符識別&#xff09;技術的實現原理涉及計算機視覺、自然語言處理&#xff08;NLP&#xff09;和深度學習等多個領域的融合&#xff0c;其核心目標是讓計算機能夠準確識別并理解不同語言的印刷或手寫文本。以下是其關鍵技術實現原理的詳細解析&#…

GPT:讓機器擁有“創造力”的語言引擎

當ChatGPT寫出莎士比亞風格的十四行詩&#xff0c;當GitHub Copilot自動生成編程代碼&#xff0c;背后都源于同一項革命性技術——**GPT&#xff08;Generative Pre-trained Transformer&#xff09;**。今天&#xff0c;我們將揭開這項“語言魔術”背后的科學原理&#xff01;…

LeetCode|Day19|14. 最長公共前綴|Python刷題筆記

LeetCode&#xff5c;Day19&#xff5c;14. 最長公共前綴&#xff5c;Python刷題筆記 &#x1f5d3;? 本文屬于【LeetCode 簡單題百日計劃】系列 &#x1f449; 點擊查看系列總目錄 >> &#x1f4cc; 題目簡介 題號&#xff1a;14. 最長公共前綴 難度&#xff1a;簡單…

安全事件響應分析--基礎命令

----萬能密碼oror1 or # 1or11 1 or 11安全事件響應分析------***windoes***------方法開機啟動有無異常文件 【開始】?【運行】?【msconfig】文件排查 各個盤下的temp(tmp)相關目錄下查看有無異常文件 &#xff1a;Windows產生的 臨時文件 可以通過查看日志且通過篩…

基于C#+SQL Server實現(Web)學生選課管理系統

學生選課管理系統的設計與開發一、項目背景學生選課管理系統是一個學校不可缺少的部分&#xff0c;傳統的人工管理檔案的方式存在著很多的缺點&#xff0c;如&#xff1a;效率低、保密性差等&#xff0c;所以開發一套綜合教務系統管理軟件很有必要&#xff0c;它應該具有傳統的…

垃圾回收(GC)

內存管理策略&#xff0c;在業務進程運行的過程中&#xff0c;由垃圾收集器以類似守護協程的方式在后臺運行&#xff0c;按照指定策略回收不再被使用的對象&#xff0c;釋放內存空間進行回收 優勢&#xff1a; 屏蔽內存回收的細節&#xff1a;屏蔽復雜的內存管理工作&#xff0…

Datawhale AI夏令營-機器學習

比賽簡介 「用戶新增預測挑戰賽」是由科大訊飛主辦的一項數據科學競賽&#xff0c;旨在通過機器學習方法預測用戶是否為新增用戶 比賽屬于二分類任務&#xff0c;評價指標采用F1分數&#xff0c;分數越高表示模型性能越好。 如果你有一份帶標簽的表格型數據&#xff0c;只要…

Spring IOC容器在Web環境中是如何啟動的(源碼級剖析)?

文章目錄一、Web 環境中的 Spring MVC 框架二、Web 應用部署描述配置傳統配置&#xff08;web.xml&#xff09;&#xff1a;Java配置類&#xff08;Servlet 3.0&#xff09;&#xff1a;三、核心啟動流程詳解1. 啟動流程圖2. ★容器初始化入口&#xff1a;ContextLoaderListene…

18個優質Qt開源項目匯總

1&#xff0c;Clementine Music Player Clementine Music Player 是一個功能完善、跨平臺的開源音樂播放器&#xff0c;非常適合用于學習如何開發媒體類應用&#xff0c;尤其是跨平臺桌面應用。它基于 Qt 框架開發&#xff0c;支持多種操作系統&#xff0c;包括 Windows、macO…

計算機視覺:AI 的 “眼睛” 如何看懂世界?

1. 什么是計算機視覺&#xff1a;讓機器 “看見” 并 “理解” 的技術1.1 計算機視覺的核心目標計算機視覺&#xff08;CV&#xff09;是人工智能的一個重要分支&#xff0c;它讓計算機能夠 “看懂” 圖像和視頻 —— 不僅能捕捉像素信息&#xff0c;還能分析內容、提取語義&am…

華為OD刷題記錄

華為OD刷題記錄 刷過的題 入門 1、進制 2、NC61 doing 訂閱專欄

QT學習教程(二十五)

雙緩沖技術&#xff08;Double Buffering&#xff09;&#xff08; 2、公有函數實現&#xff09;#include <QtGui> #include <cmath> using namespace std; #include "plotter.h"以上代碼為文件的開頭&#xff0c;在這里把std 的名空間加入到當前的全…

設計模式筆記_結構型_裝飾器模式

1.裝飾器模式介紹裝飾器模式是一種結構型設計模式&#xff0c;允許你動態地給對象添加行為&#xff0c;而無需修改其代碼。它的核心思想是將對象放入一個“包裝器”中&#xff0c;這個包裝器提供了額外的功能&#xff0c;同時保持原有對象的接口不變。想象一下&#xff0c;你有…

day25 力扣90.子集II 力扣46.全排列 力扣47.全排列 II

子集II給你一個整數數組 nums &#xff0c;找出并返回所有該數組中不同的遞增子序列&#xff0c;遞增子序列中 至少有兩個元素 。你可以按 任意順序 返回答案。數組中可能含有重復元素&#xff0c;如出現兩個整數相等&#xff0c;也可以視作遞增序列的一種特殊情況。示例 1&…