- 在設計模式中,觀察者模式能夠算得上是一種很是經典的行爲設計模式,事件---事件發佈者---事件監聽者是事件驅動模型在設計層面的體現.
- 在
Spring
容器中經過ApplicationEvent
類和ApplicationListener
接口來處理事件的.若是某個bean
實現ApplicationListener
接口並被部署到容器中,那麼每次對應的ApplicationEvent
被髮布到容器中都會通知該bean
,這是典型的觀察者模式.Spring
的事件默認是同步的,即調用#publishEvent
方法發佈事件後,它會處於阻塞狀態,直到#onApplicationEvent
接受到事件並處理返回以後才繼續執行下去,這種單線程同步的好處是能夠進行事務管理.- 系統默認提供的容器事件的異步發佈機制參數
事件java
- 其繼承自
JDK
的EventObject
,JDK
要求全部的事件都繼承它,並經過#resource
獲得事件源,咱們的AWT事件體系也是繼承自它.- 系統默認提供以下
ApplicationEvent
事件:
目標(事件發佈者)設計模式
- 具體表明:
ApplicationEventPublisher
和ApplicationEventMulticaster
,系統提供以下實現:
ApplicationContext
接口繼承了ApplicationEventPublisher
,並在abstractApplicationContext#publishEvent
方法實現具體代碼,實際執行委託給ApplicationEventMulticaster#multicastEvent
方法.ApplicationContext#initApplicationEventMulticaster
方法會自動到本地容器裏找一個名爲ApplicationEventMulticaster
的實現,若是沒有就new
一個SimpleApplicationEventMulticaster
.- 能夠看到若是提供一個
executor
,它就能夠異步支持發佈事件,不然爲同步發佈.
監聽器異步
具體表明:
ApplicationListener
源碼分析
- 其繼承自
JDK
的EventListener
,JDK
要求全部的監聽器將繼承它,好比咱們的AWT
事件體系也是繼承自它.ApplicationListener
接口:其只提供了#onApplicationEvent
方法,咱們須要在該方法實現內部判斷事件類型來處理,若想提供順序觸發監聽器的語義,則可使用另外一個接口:SmartApplicationListener
現假設一個用戶註冊的案例場景.用戶註冊後,系統須要給用戶發送郵件告知用戶註冊是否成功,須要給用戶初始化積分,後續可能會添加其餘的操做,如再發一條手機短信等,但願程序具備拓展性符合開閉原則.spa
- 若是不使用事件驅動,代碼可能會像這個樣子:
![]()
要說代碼有什麼問題其實也不算,由於大多數人在開發時第一直覺都會這麼寫,寫同步代碼.可是這麼寫,實際上並非特別符合隱含的設計需求,假設增長更多的註冊項
Service
,咱們須要修改#register
方法,並讓UserService
注入對應的Service
.而實際上register
並不關心這些"額外"的操做,如何將這些代碼抽取出去,這時能夠考慮Event
機制.線程
定義用戶註冊事件設計
ApplicationEvent
是由Spring
提供的全部Event
類的基類,這裏爲了簡單隻傳遞name
.
定義用戶註冊服務(事件發佈者)3d
- 服務交給
Spring
容器管理.ApplicationEventPublishAware
是由Spring
提供的用於Service
注入ApplicationEventPublisher
事件發佈器的接口.使用這個接口,咱們的Service
就擁有發佈事件的能力了.- 用戶註冊後,再也不是顯示調用其餘的業務
Service
,而是發佈一個用戶註冊事件
定義郵件服務,積分服務,其餘服務(事件訂閱者)code
- 事件訂閱者的服務一樣須要託管於
Spring
容器ApplicationListener<E extends ApplicationEvent>
接口是Spring
提供的事件訂閱者必須實現的接口,咱們通常把Service
關心的事件做爲泛型傳入.- 事件處理:
ApplicationEvent#getSource
拿到事件的具體內容,本例中爲name
.
- 當發佈多個事件的時候,他們的順序是無序的.若是要控制順序,則監聽器
Service
須要實現Order
接口或者使用SmartApplicationEventListener
.- 經過
Spring
事件驅動模型,咱們完成了註冊服務和其餘服務之間的解耦,這也是事件驅動的最大特性之一,若後續要新增其餘操做,只須要添加相應的事件訂閱者便可.
supportsEventType
:用於指定支持的事件類型,只有支持的才調用#onApplicationEvent
方法.supportsSourceType
:支持的目標類型,只有支持的才調用#onApplicationEvent
方法.getOrder
:順序越小優先級越高,監聽器默認優先級爲7
.
- 註解式的事件發佈者:
Spring4.2
以後,ApplicationEventPublisher
自動被注入到容器中,再也不須要顯示實現Aware
接口
- 註解式的事件訂閱者:
@EventListener
註解完成了ApplicationListener<E extends ApplicationEvent>
接口的使命.
java
配置經過@EnableAsync
模塊註解開啓異步支持,使用@Async
註解對須要異步的監聽器進行標註.
- 事件(
ApplicationEvent
):繼承JDK
的EventObject
在Spring
項目中能夠繼承ApplicationEvent
來定義本身的事件事件發佈者(
Application
):實現這個接口,就可使得Spring
組件有發佈事件的能力,ApplicationContext
實現了此接口,所以,發佈事件的方式有以下幾種:對象
- 經過實現
ApplicationEventPublisherAware
接口,獲取注入的ApplicationPublisher
對象來進行事件發佈.- 經過實現
ApplicationContextAware
接口,獲取注入的ApplicationContext
來進行事件發佈.- 經過
@autowired
註解直接注入ApplicationEventPublisher
或者ApplicationContext
對象來調用AbstractApplicationContext#publishEvent
來委託ApplicationEventMulticaster
進行事件發佈
- 經過源碼分析,在
AbstractApplicationContext
類中,定義了針對觀察者的add,get,register
等方法,經過這一系列的方法向ApplicationEventMulticaster
類中維護listener
集合Set
.改Set
存儲了該發佈者全部的Listener
,因此ApplicationContext
容器會將注入到Spring
中的Listener
註冊到ApplicationEventMulticaster
中
- 事件經過
AbstractApplicationContext#publishEvent
方法委託給AbstractApplicationEventMulticaster
進行事件發佈,其中ApplicationEventMulticaster
會先嚐試從ConfigurableListableBeanFactroy
中加載配置文件的類,若是不存在就會默認new
一個SimpleApplicationEventMulticaster
.
- 具體的事件發佈會在
AbstractApplicaitonEventMulticaster#multicastEvent
中實現,實現流程爲:先根據event
獲取Listener
集合,在線程池不爲空的狀況下,異步發佈特定類型的事件,不然同步發佈.在#invokeListener
方法中最後調用Listener#onApplicationEvnet
方法實現了事件的發佈.
- 以上就是關於
Spring
事件監聽機制的分析,其本質上是觀察者模式的實現.經過事件監聽機制可以將咱們代碼邏輯進行解耦,提升代碼的拓展性,實現開閉原則.