📢 大家好,我是 【戰神劉玉棟】,有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 監聽器的用法,僅供參考。
監聽器用的最多的場景,還是初始化監聽器,程序啟動之前執行一些諸如,數據加載到緩存等動作。
💗 后續企業實戰或源碼分析會詳細展開。