《知識點掃盲 · 監聽器 Listener》

📢 大家好,我是 【戰神劉玉棟】,有10多年的研發經驗,致力于前后端技術棧的知識沉淀和傳播。 💗
🌻 CSDN入駐不久,希望大家多多支持,后續會繼續提升文章質量,絕不濫竽充數,如需交流,歡迎留言評論。👍

文章目錄

    • 寫在前面的話
    • **監聽器簡介**
    • Servlet 監聽器
    • Spring 監聽器
      • 實現 ApplicationListener 接口
      • 使用 @EventListener 注解
      • Spring 常見內置事件
      • 自定義事件與監聽器
      • Spring 監聽器原理分析
      • 實戰 · 初始化監聽器拓展
    • 其他監聽器
    • 總結陳詞


寫在前面的話

上幾篇博文介紹了攔截器 Interceptor和過濾器 Filter,這邊接著介紹一下監聽器、切面等內容,先把這一系列補充完畢,之前列的類目太廣,精力有限,導致很多其他系列沒接著更新,被粉絲催促。還是經驗不足導致,后續改善。
話分兩頭,本篇文章讓我們進入監聽器 Listener的世界。


監聽器簡介

監聽器是一種常見的設計模式,廣泛應用于各種編程場景中。不同的框架和庫都有自己的監聽器機制,適用于不同類型的事件處理需求(這點和前面介紹的攔截器很像)。通過監聽器,開發者可以實現事件驅動的編程模型,解耦事件的產生和處理邏輯,從而提高代碼的可維護性和擴展性。
簡單來說, 監聽器用于監聽一些重要事件的發生,以便在事情發生前、發生后可以做一些必要的處理。
場景舉例:項目啟動時,需要做一些預處理和初始化操作,如緩存預加載等,服務關閉時,清理線程資源等;


Servlet 監聽器

Java Servlet 規范中定義了幾種類型的監聽器,用于監聽 Web 應用程序生命周期中的各種事件。
下面展開介紹常見的幾種。

1、ServletContextListener 和 ServletContextAttributeListener
ServletContextListener 可以監聽到 ServletContext 的創建和銷毀,而 ServletContextAttributeListener 可以監聽到ServletContext 中屬性的新增、移除和屬性值的替換。

2、HttpSessionListener 和 HttpSessionAttributeListener
HttpSessionListener 可以監聽 HttpSession 的創建跟銷毀,而 HttpSessionAttributeListener 則是對 HttpSession 中屬性的監聽,它可以監聽到 HttpSession 新增屬性、移除屬性和屬性值被替換時;

3、ServletRequestListener 和 ServletRequestAttributeListener
ServletRequestListener 可見監聽 Request 的創建和銷毀;而 ServletRequestAttributeListener 可以對 Request 的屬性進行監聽;

上面三種從命名上也很好理解,邏輯也差不多,示例代碼如下:

@Slf4j
@Component
public class ServletInitListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {if (log.isInfoEnabled()) {log.info("Servlet啟動初始化監聽~");}}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {if (log.isInfoEnabled()) {log.info("Servlet啟動初始化監聽~");}}
}

如果是SpringBoot項目,那如何讓其生效?有兩種方式:
1、實現監聽器類后,直接加上 @Component 注解,推薦這種方式,這種方式下,你可以使用 Spring 的依賴注入功能,因為監聽器類是一個 Spring Bean;
2、實現監聽器類后,加上 @WebListener 注解,使用該標簽時,需要在啟動類上使用 @ServletComponentScan 注解,這種方式就單純當作監聽器處理,不要用依賴諸如方式操作 Bean,一定要使用就借助 SpringUtil 等方式,并且要考慮容器加載順序問題;

總之,很簡單的用法,總結就是 Servlet 監聽器可以監聽 ServletContext、HttpSession、ServletRequest 對象的生命周期事件以及屬性改變事件。其作用是監聽一些重要事件的發生,監聽器對象可以在事情發生前、發生后可以做一些必要的處理。


Spring 監聽器

參考:鏈接 鏈接
前面介紹完了 Servlet 監聽器,比較簡單,而真正在 Spring 項目的開發中,用 Spring 監聽器的場景更多。
先了解一下最常見的示例:

實現 ApplicationListener 接口

下面示例監聽 ContextRefreshedEvent 事件,該方法在應用程序上下文被刷新時觸發,該事件是 Spring 框架內置事件,由 Spring 框架執行到某一個時刻觸發,我們就負責接收通知,這是其中一種觀察者方式。

@Slf4j
@Component
public class SpringInitListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if (event.getSource() instanceof AnnotationConfigServletWebServerApplicationContext) {if (log.isInfoEnabled()) {log.info("【SpringInitListener】Spring啟動初始化監聽,應用程序上下文已刷新~");}//執行主業務邏輯doBiz();}}/*** 執行業務邏輯*/private void doBiz() {}
}

使用 @EventListener 注解

該方式不需要繼承或實現任何其他類,然后在它的某個方法上加上 @EventListener 注解,效果差不多。

@Slf4j
@Component
public class MySpringListener {@EventListener(ContextRefreshedEvent.class)public void methodA(ContextRefreshedEvent event) {if (log.isInfoEnabled()) {log.info("【MySpringListener】Spring啟動初始化監聽,應用程序上下文已刷新~");}}
}

Spring 常見內置事件

上面示例中,我們使用了一個 ContextRefreshedEvent 的事件,這個事件是Spring內置的事件,除了該事件,Spring還內置了一些其他的事件類型,分別在以下情況下觸發。

Tips:不是很需要掌握全部的事件,按需使用。

SpringBoot Application 共支持6種事件監聽,按順序分別是:

  • ApplicationStartingEvent:在Spring最開始啟動的時候觸發
  • ApplicationEnvironmentPreparedEvent:在Spring已準備好上下文但是上下文尚未創建的時候觸發
  • ApplicationPreparedEvent:在Bean定義加載之后、刷新上下文之前觸發
  • ApplicationStartedEvent:在刷新上下文之后、調用application命令之前觸發
  • ApplicationReadyEvent:在調用applicaiton命令之后觸發
  • ApplicationFailedEvent:在啟動Spring發生異常時觸發

Spring 的5個標準事件:

  • 上下文更新事件(ContextRefreshedEvent):該事件會在ApplicationContext被初始化或者更新時發布。也可以在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。
  • 上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
  • 上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
  • 上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀。
  • 請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。

自定義事件與監聽器

就下面三個步驟,可以直接看代碼,前面示例翻新一下:
Step1、建立繼承自ApplicationEvent的自定義事件類;
Step2、使用@EventListener注解來實現監聽;
Step3、發布事件;

@Slf4j
@Component
public class MySpringListener {/*** 監聽Spring內置事件*/@EventListener(ContextRefreshedEvent.class)public void methodA(ContextRefreshedEvent event) {if (log.isInfoEnabled()) {log.info("【MySpringListener】Spring啟動初始化監聽,應用程序上下文已刷新~");}}/*** 監聽自定義事件*/@EventListener(MyCustomEvent.class)public void methodB(MyCustomEvent event) {log.info("========我監聽到自定義事件了:" + event.getMessage());}/*** 再次監聽自定義事件*/@EventListener(MyCustomEvent.class)public void methodC(MyCustomEvent event) {log.info("========我監聽到自定義事件了:" + event.getMessage());}
}@Getter
@Setter
public class MyCustomEvent extends ApplicationEvent {private String message;public MyCustomEvent(Object source, String message) {super(source);this.message = message;}
}@Slf4j
@Component
public class SpringInitListener implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if (event.getSource() instanceof AnnotationConfigServletWebServerApplicationContext) {if (log.isInfoEnabled()) {log.info("【SpringInitListener】Spring啟動初始化監聽,應用程序上下文已刷新~");}// 發布自定義事件MyCustomEvent myCustomEvent = new MyCustomEvent(applicationContext, "這是自定義事件,我發布了");applicationContext.publishEvent(myCustomEvent);// 執行主業務邏輯doBiz();}}/*** 執行業務邏輯*/private void doBiz() {}
}

Spring 監聽器原理分析

這里簡單說一下Spring監聽器的實現原理。
Spring 的監聽器用到了觀察者模式、工廠模式、適配器模式,以觀察者模式為主,可用于松散耦合,改進代碼管理和潛在的復用。
通俗來說,就是創建一個主題對象,主題對象維護一個觀察者列表,當主題對象的狀態發生變化時,它會遍歷觀察者列表,并調用每個觀察者的通知方法。觀察者接收到通知后,根據通知進行相應的更新操作。
舉例說明,當抖音的某個海賊王博主,很多粉絲關注了它的海賊王專欄,就屬于它的觀察者,當博主更新了海賊王1100集漫畫的講解視頻,這些粉絲在抖音在線的狀態,會收到該視頻的更新通知,可以快速點擊進去,一睹為快。
這個模式其實很好理解,可能很多場景都遇到過它的變種。消息中心的事件驅動機制,Redis-Key的發布訂閱機制,都是基于觀察者模式擴展而來,運用范圍相當廣。
由于本篇文章是知識點掃盲系統,屬于技術入門,后續企業實戰或源碼分析會詳細展開。


實戰 · 初始化監聽器拓展

本來內容寫到這邊差不多了,但是感覺好像太少一些,實戰部分的還是分享一些。
顯然,這個用法很簡單,關于 ContextRefreshedEvent 的初始化監聽,作為具體某個模塊的開發人員完全可以寫一個 Spring 監聽器類,完成自己想要的初始化動作,So easy~
但該用法存在一些局限性:
首先,該操作是同步的,若初始化執行的程序邏輯耗時較多,會影響整個服務的啟動時長,進而引發一系列問題,例如KS8誤判啟動失敗等;
其次,該操作中,只要業務邏輯存在未把控到位的情況,意外拋出了異常,那么將直接導致程序啟動失敗,這可能是違背初衷的;
總之,這兩點因素帶來的影響都很大,那么作為一個框架搭建人員,如何應對這些現象,如何給開發人員更靈活的編碼體驗,這個是需要我們思考的。
參考:《框架封裝 · 自定義初始化事件》


其他監聽器

除了上面介紹的 Spring 和 Servlet 之外,其他技術也有監聽器,簡單介紹一些,不展開。

1、JavaScript 監聽器
JavaScript 廣泛應用于前端開發,瀏覽器提供了多種事件監聽機制。
關鍵詞: addEventListener

2、Kafka 監聽器
Apache Kafka 提供了事件監聽機制,用于處理消息隊列中的事件。

@KafkaListener(topics = "myTopic", groupId = "myGroup")
public void listen(String message) {System.out.println("Received message: " + message);
}

3、Hibernate 監聽器
Hibernate 提供了事件監聽器,用于監聽實體對象的生命周期事件。

//PreInsertEventListener、PostInsertEventListener:監聽實體插入事件。
public class MyPreInsertEventListener implements PreInsertEventListener {@Overridepublic boolean onPreInsert(PreInsertEvent event) {return false;}
}

總結陳詞

上文介紹了監聽器的用法,主要介紹了 Spring 監聽器的用法,僅供參考。
監聽器用的最多的場景,還是初始化監聽器,程序啟動之前執行一些諸如,數據加載到緩存等動作。
💗 后續企業實戰或源碼分析會詳細展開。

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

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

相關文章

高效前端開發:解密pnpm的存儲與鏈接

什么是pnpm PNPM&#xff08;Performant NPM&#xff09;是一種快速且節省磁盤空間的包管理工具。相較于其他包管理器如NPM和Yarn&#xff0c;PNPM通過獨特的存儲機制和鏈接技術解決了許多常見的問題。以下是PNPM如何避免這些問題以及其關鍵技術的詳細介紹。 特性 PNPM Store…

批量注冊工具是什么

摘要&#xff1a;批量注冊工具作為自動化領域的一個分支&#xff0c;為用戶在多平臺賬號管理中提供了極大的便利。 關鍵詞 批量注冊&#xff0c;自動化&#xff0c;實戰代碼&#xff0c;設計原則&#xff0c;法律法規 1. 引言 批量注冊工具能夠在短時間內創建大量賬號&…

【MySQL備份】Percona XtraBackup總結篇

目錄 1.前言 2.問題總結 2.1.為什么在恢復備份前需要準備備份 2.1.1. 保證數據一致性 2.1.2. 完成崩潰恢復過程 2.1.3. 解決非鎖定備份的特殊需求 2.1.4. 支持增量和差異備份 2.1.5. 優化恢復性能 2.2.Percona XtraBackup的工作原理 3.注意事項 1.前言 在歷經了詳盡…

數據庫、創建表、修改表

一、數據庫 1、登陸數據庫 2、創建數據庫zoo 3、修改數據庫zoo字符集為gbk 4、選擇當前數據庫為zoo 5、查看創建數據庫zoo信息 6、刪除數據庫zoo 二、創建表 1、創建一個名稱為db_system的數據庫 2、在該數據庫下創建兩張表&#xff0c;具體要求如下 員工表 user…

圖像的對數變換

對數變換在圖像處理中通常有以下作用&#xff1a; 因為對數曲線在像素值較低的區域斜率較大&#xff0c;像素值較高的區域斜率比較低&#xff0c;所以圖像經過對數變換之后&#xff0c;在較暗的區域對比度將得到提升&#xff0c;因而能增強圖像暗部的細節。圖像的傅里葉頻譜其…

MySQL 結構的優化方案

主要是指三方面&#xff0c;即表結構、字段結構以及索引結構&#xff0c;這些結構如果不合理&#xff0c;在某些場景下也會影響數據庫的性能&#xff0c;因此優化時也可以從結構層面出發。一般在項目的庫表設計之初就要考慮&#xff0c;當性能瓶頸出現時再調整結構&#xff0c;…

Python函數語法詳解(與C++對比學習)【未完】

一、Python函數的形式 def function_name (參數, ...) -> return value_type:# 函數體return value# 看具體需求# 如果沒有return語句&#xff0c;函數執行完畢后也會返回結果# 只是結果為None。return None可以簡寫為return 1. Python的返回值 在Python3中&#xff0c;提…

利用Redis bitmap 實現簽到案例

數據庫實現 設計簽到功能對應的數據庫表 CREATE TABLE sign_record (id bigint NOT NULL AUTO_INCREMENT COMMENT 主鍵,user_id bigint NOT NULL COMMENT 用戶id,year year NOT NULL COMMENT 簽到年份,month tinyint NOT NULL COMMENT 簽到月份,date date NOT NULL COMMENT 簽…

EI檢索被認為是工程技術領域的權威數據庫

EI檢索被認為是工程技術領域的權威數據庫&#xff0c;能夠被EI檢索收錄的期刊和會議論文通常被認為具有一定的學術質量和影響力。然而&#xff0c;EI檢索與“高水平”不能完全畫等號&#xff0c;以下是一些需要考慮的因素&#xff1a; 1. 收錄標準&#xff1a;雖然EI檢索有嚴格…

在Linux操作系統中關于邏輯卷的案例

1.如何去創建一個邏輯卷 1.1先去創建物理卷 如上圖所示&#xff0c;physical volume 物理卷 被成功創建。 如上圖所示&#xff0c;可以使用pvscan來去查看當前Linux操作系統的物理卷/ 1.2使用創建好的物理卷去創建一個卷組。 如上圖所示&#xff0c;可以使用第一步創建的兩個…

【中項第三版】系統集成項目管理工程師 | 第 9 章 項目管理概論③ | 9.6 - 9.10

前言 第 9 章對應的內容選擇題和案例分析都會進行考查&#xff0c;這一章節理論性較強&#xff0c;學習要以教材為準。本章分值預計在4-5分。 目錄 9.6 項目管理過程組 9.7 項目管理原則 9.8 項目管理知識領域 9.9 價值交付系統 9.10 本章練習 9.6 項目管理過程組 項目…

千萬不能踏入的渠道管理五大誤區!【附策略】

一、引言 在當今激烈的市場競爭環境中&#xff0c;有效的渠道管理是企業獲得競爭優勢的關鍵。然而&#xff0c;在實踐過程中&#xff0c;不少企業因陷入管理誤區而影響了市場拓展和品牌建設。本文旨在揭示渠道管理中常見的五大誤區&#xff0c;并提供避免策略&#xff0c;幫助…

高級Redis之Stream的用法示例

不想自己搭建一個mq怎么辦&#xff1f;Redis的Stream 來幫你&#xff0c;Redis Stream 是 Redis 5.0 引入的一種新的數據結構&#xff0c;用于處理實時的、可持久化的、基于時間序列的數據流。它非常適合處理事件流、日志、消息隊列等場景。下面是一個使用 Redis Stream 的具體…

web基礎與HTTP協議(企業網站架構部署與優化)

補充&#xff1a;http服務首頁文件在/var/www/html下的&#xff0c;一定是index.html命名的文件。才會顯示出來。 如果該路徑下沒有相應的文件&#xff0c;會顯示/usr/share/httpd/noindex下的index.html文件。 如果/usr/share/httpd/noindex沒有index.html文件&#xff0c;會…

BSI 第七屆萬物互聯智慧高峰論壇:主題:擁抱AI時代,標準賦能組織實現可持續發展

BSI 第七屆萬物互聯智慧高峰論壇&#xff1a;主題&#xff1a;擁抱AI時代&#xff0c;標準賦能組織實現可持續發展 主要收到 BSI 溫女士的邀請參加的本次論壇。還是學到的很多 。 在科技日新月異的時代背景下&#xff0c;BSI 第七屆萬物互聯智慧高峰論壇于[時間&#xff1a;6…

Object 類中的公共方法詳解

Object 類中的公共方法詳解 1、clone() 方法2、equals(Object obj) 方法3、hashCode() 方法4、getClass() 方法5、wait() 方法6、notify() 和 notifyAll() 方法 &#x1f496;The Begin&#x1f496;點點關注&#xff0c;收藏不迷路&#x1f496; 在 Java 中&#xff0c;Object…

AI 驅動的數據中心變革與前景

文章主要探討了AI計算時代數據中心的轉型&#xff0c;涉及計算技術的多樣性、規格尺寸和加速器的發展、大型語言模型&#xff08;LLM&#xff09;的發展、功耗和冷卻趨勢、基準測試的重要性以及數據中心的發展等方面。為大家提供深入了解AI基礎設施發展的視角。 計算技術的多樣…

Ubuntu(通用)—網絡加固—ufw+防DNS污染+ARP綁定

1. ufw sudo ufw default deny incoming sudo ufw deny in from any to any # sudo ufw allow from any to any port 5353 protocol udp sudo ufw enable # 啟動開機自啟 # sudo ufw reload 更改后的操作2. 防ARP欺騙 華為云教程 arp -d刪除dns記錄arp -a顯示arp表 ipconfi…

PTrade常見問題系列3

量化允許同時運行回測和交易的策略個數配置。 量化允許同時運行回測和交易的策略個數在哪里查看&#xff1f; 在量化服務器/home/fly/config/custom_config_conf文件中&#xff0c;其中運行回測的策略個數由backtest_switch&#xff08;是否限制普通回測個數&#xff09;及ba…

Qt 日志輸出的選擇方案有多少

Qt 日志輸出的選擇方案主要包括以下幾種&#xff1a; 使用內置的日志函數&#xff1a; qDebug()&#xff1a;用于輸出調試信息。qInfo()&#xff1a;用于輸出一般信息。qWarning()&#xff1a;用于輸出警告信息。qCritical()&#xff1a;用于輸出關鍵錯誤信息&#xff0c;表明…