Spring之事件機制詳解

源?/?CSDN? ? ? ??文/?敲代碼的小小酥
這里我們來分析Spring事件機制的原理。
先上UML圖,不熟悉UML規(guī)則的可以看UML類圖的制作規(guī)則。

下面我們對上圖中涉及到的幾個類進行講解。
ApplicationEvent:
抽象類,繼承了JDK的EventObject接口,起到包裝事件源的作用。
ApplicationListener:
實現(xiàn)了JDK的EventListener接口,起到監(jiān)聽器的作用。
在觀察者模式中,一定要有一個管理維護監(jiān)聽者列表的功能。在Spring的事件機制中,將維護監(jiān)聽者列表的功能單獨定義了一個接口,即ApplicationEventMulticaster接口。這也體現(xiàn)了單一責(zé)任原則的設(shè)計思想。我們看其源碼:
public?interface?ApplicationEventMulticaster?{
?/**
??*?Add?a?listener?to?be?notified?of?all?events.
??*?@param?listener?the?listener?to?add
??*/
?void?addApplicationListener(ApplicationListener>?listener);
?/**
??*?Add?a?listener?bean?to?be?notified?of?all?events.
??*?@param?listenerBeanName?the?name?of?the?listener?bean?to?add
??*/
?void?addApplicationListenerBean(String?listenerBeanName);
?/**
??*?Remove?a?listener?from?the?notification?list.
??*?@param?listener?the?listener?to?remove
??*/
?void?removeApplicationListener(ApplicationListener>?listener);
?/**
??*?Remove?a?listener?bean?from?the?notification?list.
??*?@param?listenerBeanName?the?name?of?the?listener?bean?to?remove
??*/
?void?removeApplicationListenerBean(String?listenerBeanName);
?/**
??*?Remove?all?listeners?registered?with?this?multicaster.
??*?After?a?remove?call,?the?multicaster?will?perform?no?action
??*?on?event?notification?until?new?listeners?are?registered.
??*/
?void?removeAllListeners();
?/**
??*?Multicast?the?given?application?event?to?appropriate?listeners.
??*?Consider?using?{@link?#multicastEvent(ApplicationEvent,?ResolvableType)}
??*?if?possible?as?it?provides?better?support?for?generics-based?events.
??*?@param?event?the?event?to?multicast
??*/
?void?multicastEvent(ApplicationEvent?event);
?/**
??*?Multicast?the?given?application?event?to?appropriate?listeners.
??*?If?the?{@code?eventType}?is?{@code?null},?a?default?type?is?built
??*?based?on?the?{@code?event}?instance.
??*?@param?event?the?event?to?multicast
??*?@param?eventType?the?type?of?event?(can?be?{@code?null})
??*?@since?4.2
??*/
?void?multicastEvent(ApplicationEvent?event,?@Nullable?ResolvableType?eventType);
}
ApplicationEventPublisher:
Spring設(shè)計的事件發(fā)布類,我們看其源碼:
public?interface?ApplicationEventPublisher?{
?/**
??*?Notify?all?matching?listeners?registered?with?this
??*?application?of?an?application?event.?Events?may?be?framework?events
??*?(such?as?ContextRefreshedEvent)?or?application-specific?events.
??*?Such?an?event?publication?step?is?effectively?a?hand-off?to?the
??*?multicaster?and?does?not?imply?synchronous/asynchronous?execution
??*?or?even?immediate?execution?at?all.?Event?listeners?are?encouraged
??*?to?be?as?efficient?as?possible,?individually?using?asynchronous
??*?execution?for?longer-running?and?potentially?blocking?operations.
??*?@param?event?the?event?to?publish
??*?@see?#publishEvent(Object)
??*?@see?org.springframework.context.event.ContextRefreshedEvent
??*?@see?org.springframework.context.event.ContextClosedEvent
??*/
?default?void?publishEvent(ApplicationEvent?event)?{
??publishEvent((Object)?event);
?}
?/**
??*?Notify?all?matching?listeners?registered?with?this
??*?application?of?an?event.
??*?If?the?specified?{@code?event}?is?not?an?{@link?ApplicationEvent},
??*?it?is?wrapped?in?a?{@link?PayloadApplicationEvent}.
??*?Such?an?event?publication?step?is?effectively?a?hand-off?to?the
??*?multicaster?and?does?not?imply?synchronous/asynchronous?execution
??*?or?even?immediate?execution?at?all.?Event?listeners?are?encouraged
??*?to?be?as?efficient?as?possible,?individually?using?asynchronous
??*?execution?for?longer-running?and?potentially?blocking?operations.
??*?@param?event?the?event?to?publish
??*?@since?4.2
??*?@see?#publishEvent(ApplicationEvent)
??*?@see?PayloadApplicationEvent
??*/
?void?publishEvent(Object?event);
}
通過上面幾個類的描述,我們總結(jié)一下spring事件機制的流程:
流程的核心,就是PublishEvent。Event對象以參數(shù)的形式傳入PublishEvent對象。然后將Event事件傳入ApplicationEventMulticaster類中,由ApplicationEventMulticaster類將事件傳給其維護的監(jiān)聽者,執(zhí)行監(jiān)聽者方法。
領(lǐng)悟
應(yīng)用
這就需要我們結(jié)合源碼進行解讀了。
筆者找到一篇寫的很好的博文,大家可以參考:淺談Spring事件監(jiān)聽。
@Component
public?class?MyEventSource?{
????public?void?ccc(){
????????System.out.println("事件源方法");
????}
}
@Component
public?class?MyEvent?extends?ApplicationEvent?{
????public?MyEvent(MyEventSource?source)?{
????????super(source);
????}
????
????public?void?eventMethod(){
????????System.out.println("事件自定義方法");
????}
}
@Component
public?class?MyListener?implements?ApplicationListener?{
????@Override
????public?void?onApplicationEvent(ApplicationEvent?applicationEvent)?{
????????if(applicationEvent?instanceof?MyEvent)?{
????????????((MyEvent)applicationEvent).eventMethod();
????????????MyEventSource?eventSource?=?(MyEventSource)?applicationEvent.getSource();
????????????eventSource.ccc();
????????????System.out.println("監(jiān)聽者發(fā)生一些改變");
????????}
????}
}
如果我們想特定的事件發(fā)布給特定的監(jiān)聽者,那我們只能自己實現(xiàn)Spring的發(fā)布類和ApplicationEventMulticaster類,自己定義事件的發(fā)布機制。
ApplicationListener類是支持泛型的,在類后定義泛型,可以過濾掉其他的事件對象,只接收泛型類事件。
public?class?MyTest?{
????@Test
????public?void?test1()?{
????????ClassPathXmlApplicationContext?applicationContext?=?new?ClassPathXmlApplicationContext("spring.xml");
????????Object?o=applicationContext.getBean("myEvent");
????????applicationContext.publishEvent(applicationContext.getBean("myEvent"));
???????
????}
}
總結(jié)
在單機環(huán)境中,我們要實現(xiàn)代碼的解耦,可以采用事件機制。例如:在前面講觀察者模式時,我們把監(jiān)聽者的放在事件類中維護的方式,就是高耦合的。而Spring將其進行了解耦。
補充:
ContextRefreshedEvent(上下文更新完成事件):在spring容器初始化流程完成后,觸發(fā)事件。事件的觸發(fā)(即調(diào)用publishEvent方法)是Spring自己調(diào)用的,我們只需定義Listener監(jiān)聽者處理業(yè)務(wù)即可。
如之前一個項目,在項目啟動的時候有一個while(true){…}死循環(huán),造成了項目無法正常啟動。當時的解決方案是將死循環(huán)另起了一個線程解決的。現(xiàn)在可以采用ContextRefreshedEvent事件解決。當容器加載完成后,再執(zhí)行死循環(huán)業(yè)務(wù)。代碼如下:
@Component
public?class?MyListener?implements?ApplicationListener?{
????@Override
????public?void?onApplicationEvent(ContextRefreshedEvent?event)?{
??????while?(true){
??????????System.out.println("執(zhí)行業(yè)務(wù)");
??????}
????}
}
END


頂級程序員:topcoding
做最好的程序員社區(qū):Java后端開發(fā)、Python、大數(shù)據(jù)、AI
一鍵三連「分享」、「點贊」和「在看」
