之前做個資料統計的需求,就是用的spring事件釋出與監聽機制(用于采集基礎資料),今天做個小小的總結。
下面我們先回顧下基礎的spring知識(beanfactory&applicationcontext的相關知識),因為spring事件釋出與監聽機制就包含在其中初始化流程的某個步驟中。
beanfacotry與applicationcontext
1、beanfactory 使用demo:
1.1 beanfactory 源碼(節選getbean()方法)
1.2 代碼分析:
此處,我們通過構造 beanfactory 的 執行個體對象 xmlbeanfactory,完成對特定xml檔案的bean資訊加載,然後通過 getbean(string beanname); 方法擷取特定的對象。
beanfactory在啟動的時候不會去執行個體化bean,二是隻有從容器中取bean的時候才會去執行個體化;
beanfactory具備延遲執行個體化的優點;
同時,beanfactory也具備不能及時發現一些存在的spring的配置問題的缺點;
2、applicationcontext 使用demo:
2.1 applicationcontext 源碼
applicationcontext 接口的關系架構圖:(applicationcontext 本質是對 beanfactory 進行了功能拓展)
applicationcontext跟beanfactory 相反,它是在容器啟動時,一次性建立了所有的bean。同時,注冊spring監聽器的工作也發生在這裡:registerlisteners();
2.2 代碼分析:
梳理下源碼的流程,見下圖:(我們這章節的重點就是從10步進行切入:注冊事件監聽器)
3、beanfacotry與applicationcontext的差別
beanfacotry是spring中比較原始的factory。如xmlbeanfactory就是一種典型的beanfactory。
原始的beanfactory無法支援spring的許多插件,如aop功能、web應用等。
applicationcontext接口,它由beanfactory接口派生而來,因而提供beanfactory所有的功能。
applicationcontext以一種更向面向架構的方式工作以及對上下文進行分層和實作繼承,applicationcontext包還提供了以下的功能: 1)messagesource, 提供國際化的消息通路 2)資源通路,如url和檔案 3)事件傳播 (我們這章節的重點) 4)載入多個(有繼承關系)上下文 ,使得每一個上下文都專注于一個特定的層次,比如應用的web層。
spring事件釋出與監聽的應用
1、事件源&事件pojo
2、事件監聽器
applicationlistener 需要設定泛型限定類,也就是上面提到的事件源。
3、釋出自定義事件
在業務的需要地方進行事件釋出:
4、代碼分析
applicationcontext事件機制是觀察者設計模式的實作。
通過applicationevent類和applicationlistener接口,可以實作applicationcontext事件處理。
如果容器中有一個applicationlistener bean,每當applicationcontext釋出applicationevent時,applicationlistener bean将自動被觸發(同步/異步的方式)。
兩個重要成員
applicationevent:容器事件,必須由applicationcontext釋出;
applicationlistener:監聽器,可由容器中的任何監聽器bean擔任。
源碼剖析
源碼剖析思路,以3個元件作為線索:
applicationevent 事件
applicationlistener 監聽器,對事件進行監聽
applicationeventmulticaster 事件廣播器,将publish的事件廣播給所有的監聽器。
元件一:事件 applicationevent 的5種實作
applicationevent 是所有事件的基礎抽象類,包括我們的自定義事件也是繼承了它。
contextrefreshedevent :當applicationcontext初始化或者重新整理,将會釋出,例如使用configurableapplicationcontext接口調用refresh方法,初始化意味着加載所有的bean,同時
contextstartedevent:當applicationcontext啟動的時候,将會調用start方法,釋出此事件。
contextstoppedevent:當容器停止的時候,釋出事件。
contextclosedevent:當容器關閉的時候,釋出事件。
requesthandledevent:http請求完成後,釋出事件。
元件二:監聽器 applicationlistener
applicationlistener:applicationcontext容器内部自定義事件監聽器接口,繼承自java.util.eventlistener,applicationcontext容器在啟動時,會自動識别并加載eventlistener類型bean的定義,一旦容器事件釋出,将會通知注冊到容器的監聽器。
元件三:廣播器applicationeventmulticaster
1、概述:釋出器 applicationeventpublisher 和 廣播器applicationeventmulticaster 的關系
applicationeventpublisher:是一個封裝事件釋出接口,作為applicationcontext父類接口。
applicationeventmulticaster:管理applicationlistener對象,并且釋出它們。
applicationcontext 委托給了 abstractapplicationeventmulticaster 來實作事件監聽器(applicationlistener)的管理。
2、釋出事件 - applicationeventpublisher
源碼 :使用了 applicationeventpublisher.publishevent() 的代碼段,可以将事件釋出出去。
源碼分析:
getapplicationeventmulticaster().multicastevent(applicationevent, eventtype);
擷取到廣播器(simpleapplicationeventmulticaster),并且将自定義事件告訴廣播器。
3、廣播器 - simpleapplicationeventmulticaster
3.1、simpleapplicationeventmulticaster 廣播器的類架構圖:
applicationeventmulticaster 接口實作類是 simpleapplicationeventmulticaster,它的 multicastevent() 方法功能是:實作了周遊監聽器清單,逐個釋出事件到監聽器中(觀察者模式的應用場景)。
代碼分析:上文提及的代碼段:getapplicationeventmulticaster() 方法便是擷取到注入的執行個體 simpleapplicationeventmulticaster,它即是applicationeventmulticaster 的實作類了。3.2、simpleapplicationeventmulticaster 内部維護了一個監聽器清單,即是一個 concurrenthashmap 進行管理的。
<code>final map<listenercachekey, cachedlistenerretriever> retrievercache = new concurrenthashmap<>(64);</code>3.3、simpleapplicationeventmulticaster 廣播事件源碼,通過multicastevent() 方法實作
代碼解析:最終調用 simpleapplicationeventmulticaster 的 invokelistener() 方法進行實質事件處理。
simpleapplicationeventmulticaster的 invokelistener() 方法源碼,最終調用了 doinvokelistener() 方法。
doinvokelistener() 最終會調用監聽器的 onapplicationevent 方法,實作監聽效果。這裡注意,方法會抛出 classcastexception 異常,因為事件源被業務處理時可能發生類型轉換失敗的情況,這樣也能夠捕獲到這類運作時異常。
代碼分析:
再走讀一下源碼,我們可以發現 simpleapplicationeventmulticaster 其實是支援異步事件通知 和同步事件通知。
而 simpleapplicationeventmulticaster 作為預設的事件廣播器,用的是同步通知的方式;但是spring給我們提供了一個解決方案來實作我們需要的異步廣播器(參考下面的小點)。
實作自定義異步廣播器?
1、自定義廣播器
@component("applicationeventmulticaster") 注解則聲明了bean的name為固定的“applicationeventmulticaster”。
2、源碼分析(自定義廣播器是如何被注冊到spring容器的)
2.1、我們走讀一下 abstractapplicationcontext 的源碼,注意到一個靜态字元串變量的值為“applicationeventmulticaster”;
2.2、同時定位到 initapplicationeventmulticaster() 方法的作用就是 initialize the applicationeventmulticaster.(初始化事件廣播器);如果可以擷取到則使用這個“applicationeventmulticaster” bean,則可以進行注冊了(其實就是擷取對象引用然後指派)。
代碼分析:當在我們自定義的多點傳播器中設定了executor時,simpleapplicationeventmulticaster 廣播器的exeutor就不為空了 ,就會走到第一個異步多點傳播的路徑。
總結
通過上文,我們複習了spring的兩大容器元件(beanfacotry與applicationcontext);進而切入到“spring事件釋出&監聽機制”:包括了它們的應用案例、底層源碼分析;最後針對spring事件廣播器的特性,拓展了如何自定義異步廣播器以及它背後的原理。希望對大家有所幫助。
掃描二維碼
擷取技術幹貨
背景技術彙