摘要:準(zhǔn)備好了我們可以開始向中發(fā)布,當(dāng)發(fā)布后,所有在中的都會(huì)收到對(duì)應(yīng)的。將類注入到的中。測(cè)試和通過(guò)方法將發(fā)布到應(yīng)用上下文中,同時(shí)這個(gè)動(dòng)作會(huì)觸發(fā)收到事件。深入剖析發(fā)布與監(jiān)聽(tīng)的過(guò)程在使用方法發(fā)布的時(shí)候,最終會(huì)調(diào)用到中的類的如下的一段代碼。
本篇主要來(lái)聊一聊spring中ApplicationListener接口和ApplicationEvent類。
從命名上可以很容易的看出來(lái)一個(gè)是listener另一個(gè)是被監(jiān)聽(tīng)的事件,但是spring是如何做到listener去監(jiān)聽(tīng)event?同時(shí)我們?cè)撊绾卧谌粘i_發(fā)過(guò)程中使用spring為我們提供的這一個(gè)監(jiān)聽(tīng)模式?
0x01 listener和event關(guān)系spring啟動(dòng)后會(huì)為我們創(chuàng)建好一個(gè)上下文,也即是我們經(jīng)常聽(tīng)到的spring IOC的上下文ApplicationContext,可以理解ApplicationContext中是初始化了所有在.xml文件配置的bean標(biāo)簽的bean。
我們通過(guò)在.xml文件中定義一個(gè)listener的bean,這個(gè)listener用來(lái)監(jiān)聽(tīng)event,listener通過(guò)實(shí)現(xiàn)方法com.boyu.budmw.test.AppListener#onApplicationEvent來(lái)對(duì)event進(jìn)行處理。
listener準(zhǔn)備好了我們可以開始向ApplicationContext中發(fā)布event,當(dāng)event發(fā)布后,所有在ApplicationContext中的listener都會(huì)收到對(duì)應(yīng)的event。
0x02 如何使用listener和event這一特性
定義event
首先我們要定義一個(gè)event,不然拿什么來(lái)觸發(fā)?
public class AppEvent extends ApplicationEvent { public AppEvent(Object source) { super(source); } public void sayHi(){ System.out.println("sayHi"); } }
定義一個(gè)event非常簡(jiǎn)單,但是需要注意,這里一定要實(shí)現(xiàn)帶有一個(gè)參數(shù)的構(gòu)造函數(shù),因?yàn)楦割怉pplicationEvent中沒(méi)有默認(rèn)的構(gòu)造方法,所以子類必須重載構(gòu)造函數(shù)。
定義listener
public class AppListener implements ApplicationListener { public void onApplicationEvent(ApplicationEvent event) { if(!(event instanceof AppEvent)){ return ; } AppEvent appEvent = (AppEvent)event; appEvent.sayHi(); } }
上面是一個(gè)listener的實(shí)現(xiàn)類,listener類必須實(shí)現(xiàn)ApplicationListener接口,同時(shí)要實(shí)現(xiàn)接口中的onApplicationEvent方法,這個(gè)方法會(huì)接收到一個(gè)event,然后可以對(duì)這個(gè)event進(jìn)行處理了。
將listener類注入到spring的ApplicationContext中。
測(cè)試listener和event
public class ListenerTest { public static void main (String args[]){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/config/applicationContext.xml"); AppEvent appEvent = new AppEvent("appEvent"); applicationContext.publishEvent(appEvent); } }
通過(guò)org.springframework.context.ApplicationEventPublisher#publishEvent方法將event發(fā)布到spring應(yīng)用上下文中,同時(shí)這個(gè)動(dòng)作會(huì)觸發(fā)listener收到event事件。
0x03 深入剖析發(fā)布與監(jiān)聽(tīng)的過(guò)程在使用org.springframework.context.ApplicationEventPublisher#publishEvent方法發(fā)布event的時(shí)候,最終會(huì)調(diào)用到spring中的org.springframework.context.event.SimpleApplicationEventMulticaster類的如下的一段代碼。
當(dāng)然這也是取決于你有沒(méi)有對(duì)applicationEventMulticaster進(jìn)行定制,如果定制了,會(huì)走到你自己定制的邏輯,下面這段是spring默認(rèn)的一段邏輯。
public void multicastEvent(final ApplicationEvent event) { for (final ApplicationListener listener : getApplicationListeners(event)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @SuppressWarnings("unchecked") public void run() { listener.onApplicationEvent(event); } }); } else { listener.onApplicationEvent(event); } } }
這段代碼一看挺簡(jiǎn)單,通過(guò)org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners(org.springframework.context.ApplicationEvent)這個(gè)方法獲得applicationContext中所有的listener,然后依次調(diào)用各個(gè)listener。
getApplicationListeners這個(gè)方法中的邏輯是從beanFactory中獲取所有的ApplicationListener對(duì)象。
0x04 這個(gè)特性有什么用?當(dāng)然這里也只能談?wù)勛约赫J(rèn)識(shí)到的應(yīng)用場(chǎng)景,event中可以定義一些復(fù)雜的對(duì)象或者叫服務(wù),這樣服務(wù)提供者就和服務(wù)的使用者徹底解耦了。
根據(jù)自己的業(yè)務(wù)場(chǎng)景可以做很多事情,期待你的補(bǔ)充。
0x05 參考這篇我想最有參考價(jià)值的東西還是spring的源碼,可以去調(diào)試相關(guān)的代碼。spring有很多有價(jià)值或者說(shuō)值得學(xué)習(xí)的設(shè)計(jì)思想,同樣編碼的規(guī)范也可以讓你學(xué)到很多,多多跟著自己的思維去調(diào)試spring源碼。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/66004.html
摘要:實(shí)體代碼如下所示恒宇少年碼云用戶名密碼創(chuàng)建內(nèi)添加一個(gè)注冊(cè)方法,該方法只是實(shí)現(xiàn)注冊(cè)事件發(fā)布功能,代碼如下所示恒宇少年碼云用戶注冊(cè)方法省略其他邏輯發(fā)布事件事件發(fā)布是由對(duì)象管控的,我們發(fā)布事件前需要注入對(duì)象調(diào)用方法完成事件發(fā)布。 ApplicationEvent以及Listener是Spring為我們提供的一個(gè)事件監(jiān)聽(tīng)、訂閱的實(shí)現(xiàn),內(nèi)部實(shí)現(xiàn)原理是觀察者設(shè)計(jì)模式,設(shè)計(jì)初衷也是為了系統(tǒng)業(yè)務(wù)邏輯之...
摘要:前言由于之前使用事件機(jī)制出現(xiàn)了問(wèn)題,所以特意去了解這塊的源碼。事件機(jī)制其實(shí)就是事件發(fā)布訂閱注意在中訂閱指的是監(jiān)聽(tīng)。 前言 由于之前使用Spring事件機(jī)制出現(xiàn)了問(wèn)題,所以特意去了解這塊的源碼。Spring事件機(jī)制其實(shí)就是事件發(fā)布/訂閱(注意在Spring中訂閱指的是監(jiān)聽(tīng))。 PS:Spring版本為5.1.5.RELEASE 源碼分析 初始化 初始化這塊關(guān)鍵是核心組件的注冊(cè) App...
摘要:背景是事件機(jī)制的一部分,與抽象類類配合來(lái)完成的事件機(jī)制。如果容器中存在的,當(dāng)調(diào)用方法時(shí),對(duì)應(yīng)的會(huì)被觸發(fā)。單元測(cè)試類執(zhí)行單元測(cè)試,會(huì)發(fā)現(xiàn)事件發(fā)布之后,監(jiān)聽(tīng)器方法被調(diào)用,日志被打印出來(lái)。 背景 ApplicationListener是Spring事件機(jī)制的一部分,與抽象類ApplicationEvent類配合來(lái)完成ApplicationContext的事件機(jī)制。 如果容器中存在Applic...
摘要:前言之前使用的事件機(jī)制來(lái)改造系統(tǒng),完成了部分模塊的解耦。但是實(shí)際使用時(shí)卻發(fā)現(xiàn)存在以下問(wèn)題當(dāng)批量推送時(shí),如果在處理的過(guò)程中拋出異常,則會(huì)導(dǎo)致后續(xù)的推送中斷。但是實(shí)際上卻是拋出異常會(huì)導(dǎo)致后續(xù)事件的推送中斷。 前言 之前使用Spring的事件機(jī)制來(lái)改造系統(tǒng),完成了部分模塊的解耦。但是實(shí)際使用時(shí)卻發(fā)現(xiàn)存在以下問(wèn)題: 當(dāng)ApplicationEventPublisher批量推送Applicati...
摘要:會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎中用到了那些設(shè)計(jì)模式中用到了那些設(shè)計(jì)模式這兩個(gè)問(wèn)題,在面試中比較常見(jiàn)。工廠設(shè)計(jì)模式使用工廠模式可以通過(guò)或創(chuàng)建對(duì)象。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問(wèn)題,已經(jīng)開源,目前已經(jīng) 41k+ Star。會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎Star: https://github.com/Snailclimb... JDK 中用到了那...
閱讀 3294·2021-11-11 16:55
閱讀 2667·2021-10-13 09:39
閱讀 2507·2021-09-13 10:27
閱讀 2216·2019-08-30 15:55
閱讀 3146·2019-08-30 15:54
閱讀 3187·2019-08-29 16:34
閱讀 1891·2019-08-29 12:41
閱讀 1127·2019-08-29 11:33