居然可以這樣監(jiān)聽,你學(xué)會了嗎?
?前面講到要使自定義注解生效需要寫一段驅(qū)動代碼,那驅(qū)動代碼什么開始執(zhí)行比較合適呢?大家可能知道答案:應(yīng)用啟動的時候。
回到具體的代碼實(shí)現(xiàn)中,假設(shè)應(yīng)用程序(客戶端或服務(wù)端)依賴了 RPC框架并且使用了Spring?環(huán)境,對Spring?比較熟悉的小伙伴應(yīng)該知道,Spring?在啟動的過程中會初始化bean?,那是不是可以在初始化bean之后去執(zhí)行這段驅(qū)動代碼呢?答案是肯定的。
查閱相關(guān)資料后,Spring 監(jiān)聽器可以實(shí)現(xiàn)上面這個訴求。
Spring 監(jiān)聽器
監(jiān)聽器在使用過程中可以監(jiān)聽某些感興趣的事件,監(jiān)聽到事件來臨時可以做出響應(yīng)處理。
Spring事件監(jiān)聽體系包括三大核心組件:事件監(jiān)聽器、事件、事件廣播器,如下圖:
Spring 監(jiān)聽器
事件廣播器
事件廣播器或者叫事件多播器負(fù)責(zé)廣播發(fā)生的事件并通知所有監(jiān)聽器,所有的事件監(jiān)聽器都會提前注冊在事件廣播器中。
事件
所有的動作都可能被定義為一個事件,事件發(fā)生后事件廣播器通知所有的監(jiān)聽器,監(jiān)聽器根據(jù)情況做出響應(yīng)。
Spring 定義了一個事件基類:ApplicationEvent,看一下源碼:
ApplicationEvent? 繼承 JDK 定義的事件基類:EventObject,
ApplicationEvent 是一個抽象類,如果需要自定義事件需要繼承這個類:
當(dāng)然 Spring 自身已經(jīng)定義了非常多的事件:
- ContextRefreshedEvent:ApplicationContext 被初始化或刷新時,該事件被發(fā)布。初始化是指所有的Bean被成功裝載,后處理Bean被檢測并激活,所有Singleton Bean 被預(yù)實(shí)例化,ApplicationContext容器已就緒可用。
- ContextStartedEvent:ApplicationContext 啟動后,該事件被發(fā)布。
- ContextStoppedEvent:ApplicationContext 停止后,該事件被發(fā)布。
- ContextClosedEvent:ApplicationContext 關(guān)閉后,該事件被發(fā)布。
以上僅僅列舉了幾個常用的 Spring 事件。
根據(jù)前面分析的業(yè)務(wù)訴求,我們期望所有的bean?初始化完之后開始執(zhí)行自定義注解的驅(qū)動代碼,所以ContextRefreshedEvent這個事件才是我們感興趣的,看一下源碼:
看起來非常簡單,繼承了ApplicationContextEvent?,繼續(xù)跟一下源碼可以發(fā)現(xiàn)ApplicationContextEvent?繼承了我們上面講的ApplicationEvent。
事件監(jiān)聽器
所有的事件監(jiān)聽器都注冊在事件廣播器中,這好比觀察者模式中的觀察者。
在 Spring 中ApplicationListener?是事件監(jiān)聽器的頂層接口,繼承自 JDK 的EventListener,所有的監(jiān)聽器都必須實(shí)現(xiàn)這個接口。
定義了一個onApplicationEvent方法,當(dāng)有感興趣的事件發(fā)生后就會執(zhí)行這個方法進(jìn)行處理。
實(shí)現(xiàn)自定義監(jiān)聽器
上面介紹了 Spring 監(jiān)聽體系的一些基礎(chǔ)知識,并通過一些源碼進(jìn)行輔助介紹,這些代碼都不是 RPC 框架要寫的,RPC 框架當(dāng)前要做的是實(shí)現(xiàn)一個自定義監(jiān)聽器監(jiān)聽感興趣的事件。
通過結(jié)合業(yè)務(wù)訴求分析出:自定義一個監(jiān)聽器用來監(jiān)聽 Spring 內(nèi)置ContextRefreshedEvent事件。
自定義的監(jiān)聽器實(shí)現(xiàn)了ApplicationListener?接口,并重寫onApplicationEvent方法,方法中待實(shí)現(xiàn)的業(yè)務(wù)邏輯是重中之重。
待實(shí)現(xiàn)的業(yè)務(wù)邏輯中需要對@ServiceExpose和@ServiceReference?這兩個注解進(jìn)行處理,@ServiceExpose?對應(yīng)服務(wù)端,@ServiceReference對應(yīng)客戶端,所以基本就是兩大塊:服務(wù)端邏輯處理和客戶端邏輯處理。
注意一下,文中提到的服務(wù)端或客戶端是站在功能角度上看的,不能片面理解,一個應(yīng)用程序(服務(wù)或微服務(wù))既可能是服務(wù)端也可能是客戶端:
Spring 監(jiān)聽器-第 2 頁
如上圖,微服務(wù) A 調(diào)用微服務(wù) B,微服務(wù) B 又調(diào)用微服務(wù) C,微服務(wù) B 在整個調(diào)用鏈中既是客戶端又是服務(wù)端。
代碼結(jié)構(gòu)
自定義監(jiān)聽器DefaultRpcListener放在 listener 包下,目前 RPC 框架代碼工程結(jié)構(gòu)如下:
小結(jié)
本小節(jié)首先學(xué)習(xí)了Spring 監(jiān)聽的基本機(jī)制,了解到監(jiān)聽體系有三大關(guān)鍵要素:事件監(jiān)聽器、事件、事件廣播器,事件監(jiān)聽器會提前注冊到事件廣播器中,當(dāng)感興趣的事件發(fā)生后事件廣播器會通知到事件監(jiān)聽器,這樣事件監(jiān)聽器就可以根據(jù)業(yè)務(wù)場景進(jìn)行響應(yīng)。
Spring 提供了事件的基類,大家可以自定義事件,當(dāng)然也可以直接使用 Spring 內(nèi)置的事件,結(jié)合 RPC 框架的業(yè)務(wù)特點(diǎn)我們發(fā)現(xiàn)ContextRefreshedEvent事件比較符合我們的訴求。
Spring 定義了事件監(jiān)聽器ApplicationListener?頂層接口,我們只需要實(shí)現(xiàn)該接口就可以自定義一個監(jiān)聽器,在監(jiān)聽器中重寫onApplicationEvent方法實(shí)現(xiàn)相應(yīng)的業(yè)務(wù)邏輯。
自定義監(jiān)聽器主要的業(yè)務(wù)邏輯包括兩大塊:服務(wù)端和客戶端,服務(wù)端邏輯主要處理@ServiceExpose?注解,客戶端邏輯主要處理@ServiceReferece注解。關(guān)于注解處理的邏輯我們下一小節(jié)詳細(xì)講解。