javascript
Spring事件机制详解
一、前言
??說(shuō)來(lái)慚愧,對(duì)應(yīng)Spring事件機(jī)制之前只知道實(shí)現(xiàn) ApplicationListener 接口,就可以基于Spring自帶的事件做一些事情(如ContextRefreshedEvent),但是最近看公司的wiki基于Spring事件的領(lǐng)域驅(qū)動(dòng)才發(fā)現(xiàn)原來(lái)還有這么多東西。
二、訂閱/發(fā)布(觀察者模式)
2.1簡(jiǎn)介
Spring是基于事件驅(qū)動(dòng)模型的,我們常用的MQ就是基于觀察者模式設(shè)計(jì)的。
事件驅(qū)動(dòng)模型也就是我們常說(shuō)的觀察者,或者發(fā)布-訂閱模型;理解它的幾個(gè)關(guān)鍵點(diǎn):
Java API實(shí)現(xiàn)和自定義實(shí)現(xiàn)觀察者模式:
Java提供了兩個(gè)接口java.util.Observable和java.util.Observer,代碼可參考https://github.com/2YSP/design-pattern/tree/master/src/cn/sp/observer
三、Spring類圖分析
?
類圖
?
事件
?
類圖
?
事件發(fā)布者
具體代表者是:ApplicationEventPublisher及ApplicationEventMulticaster,系統(tǒng)默認(rèn)提供了如下實(shí)現(xiàn):
?
ApplicationEventPublisher類圖
?
?
ApplicationEventMulticaster類圖
?
代碼如下:
?
AbstractApplicationContext發(fā)布事件代碼
?
?
ApplicationEventMulticaster初始化邏輯
2.根據(jù)上面代碼可以看出 ApplicationContext 會(huì)自動(dòng)在本地容器找一個(gè)ApplicationEventMulticaster的實(shí)現(xiàn),如果沒(méi)有自己new一個(gè)SimpleApplicationEventMulticaster,其中SimpleApplicationEventMulticaster發(fā)布事件的代碼如下:
?
?
發(fā)布事件方法
可以看出如果給它一個(gè)executor,它就可以實(shí)現(xiàn)異步發(fā)布事件了,否則就是同步發(fā)送。
?
監(jiān)聽(tīng)器
ApplicationListener 接口提供了onApplicationEvent方法,但是我們需要在該方法實(shí)現(xiàn)內(nèi)部判斷事件類型來(lái)處理,也沒(méi)有提供按順序觸發(fā)監(jiān)聽(tīng)器的語(yǔ)義,所以Spring提供了另一個(gè)接口,SmartApplicationListener:
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {//如果實(shí)現(xiàn)支持該事件類型 那么返回trueboolean supportsEventType(Class<? extends ApplicationEvent> eventType);//如果實(shí)現(xiàn)支持“目標(biāo)”類型,那么返回trueboolean supportsSourceType(Class<?> sourceType);//順序,即監(jiān)聽(tīng)器執(zhí)行的順序,值越小優(yōu)先級(jí)越高int getOrder();}源碼分析到這里,下面說(shuō)說(shuō)怎么使用。
四、簡(jiǎn)單實(shí)現(xiàn)(實(shí)現(xiàn)ApplicationListener接口)
場(chǎng)景是我們保存一個(gè)訂單后發(fā)布事件通知,以便做一些其他操作比如鎖定商品。
訂單實(shí)體類:
訂單創(chuàng)建事件OrderCreateEvent
public class OrderCreateEvent extends ApplicationEvent {private final Order order;public OrderCreateEvent(Object source,Order order) {super(source);this.order = order;}public Order getOrder(){return order;} }OrderService
監(jiān)聽(tīng)器OrderCreateEventListener
運(yùn)行測(cè)試類:
(SpringRunner.class) public class ApplicationEventDemoApplicationTests {OrderService orderService;public void contextLoads() {orderService.save();}}控制臺(tái)打印如下則表示成功實(shí)現(xiàn)了監(jiān)聽(tīng)。
訂單保存成功:Order{orderNo='20190601983801', orderStatus='待付款', goods='手機(jī)', createTime=Sat Jun 01 00:23:58 CST 2019} 2019-06-01 00:23:58.069 INFO 15060 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' cn.sp.listener.OrderCreateEventListener -- ApplicationListener 接口實(shí)現(xiàn),訂單號(hào)[20190601983801]:,鎖定商品[手機(jī)] ================五、注解驅(qū)動(dòng)@EventListener
接著上面的,自定義的監(jiān)聽(tīng)器一定要實(shí)現(xiàn)ApplicationListener接口嗎?不是,Spring還提供了注解的方式 @EventListener,使用示例如下:
public class OrderCreateEventListenerAnnotation {public void createOrderEvent(OrderCreateEvent event){System.out.println(this.getClass().getName()+"--訂單創(chuàng)建事件,@EventListener注解實(shí)現(xiàn),orderNo:"+event.getOrder().getOrderNo());} }注意:@EventListener有個(gè)condition屬性,還可以支持條件判斷(定義布爾SpEL表達(dá)式),只有滿足條件才會(huì)觸發(fā),后面泛型支持那里有示例。
六、異步事件
上面的監(jiān)聽(tīng)事件都是同步觸發(fā)的,如果想異步的怎么辦?
只需要兩步:
七、泛型支持
事件類一定要繼承ApplicationEvent嗎?
當(dāng)然不是,我們還可以自定義泛型類實(shí)現(xiàn)事件調(diào)度(這個(gè)是我認(rèn)為最厲害的地方了)。
applicationEventPublisher.publishEvent(new OrderGenericEvent(order,true));
測(cè)試結(jié)果表明,成功處理了事件。
?
success為true時(shí)
我們把發(fā)布事件的代碼改為如下內(nèi)容再測(cè)試,則不會(huì)收到事件通知。
applicationEventPublisher.publishEvent(new OrderGenericEvent(order,false));
?
八、事件傳播機(jī)制
當(dāng)我們監(jiān)聽(tīng)一個(gè)事件處理完成時(shí),還需要發(fā)布另一個(gè)事件,一般我們想到的是調(diào)用ApplicationEventPublisher#publishEvent發(fā)布事件方法,但Spring提供了另一種更加靈活的新的事件繼續(xù)傳播機(jī)制,監(jiān)聽(tīng)方法返回一個(gè)事件,也就是方法的返回值就是一個(gè)事件對(duì)象。
示例代碼:
訂單監(jiān)聽(tīng)器
public class OrderListener {public void orderListener(Order order){System.out.println(this.getClass().getName() + " -- 監(jiān)聽(tīng)一個(gè)訂單");}public OrderCreateEvent orderReturnEvent(Order order){System.out.println(this.getClass().getName() + " -- 監(jiān)聽(tīng)一個(gè)訂單,返回一個(gè)新的事件 OrderCreateEvent");return new OrderCreateEvent(this,order);} }啟動(dòng)單元測(cè)試,就會(huì)發(fā)現(xiàn)OrderCreateEventListener也被觸發(fā)了。
?
enter description here
當(dāng)然還可以返回多個(gè)事件,不再舉例。
?
九、事物事件@TransactionalEventListener
從Spring 4.2開(kāi)始,框架提供了一個(gè)新的@TransactionalEventListener注解,它是@EventListener的擴(kuò)展,允許將事件的偵聽(tīng)器綁定到事務(wù)的一個(gè)階段。綁定可以進(jìn)行以下事務(wù)階段:
上面代碼的意思是僅當(dāng)存在事件生成器正在運(yùn)行且即將提交的事務(wù)時(shí),才會(huì)調(diào)用此偵聽(tīng)器。并且,如果沒(méi)有正在運(yùn)行的事務(wù),則根本不發(fā)送事件,除非我們通過(guò)將fallbackExecution 屬性設(shè)置為true來(lái)覆蓋它 ,即 @TransactionalEventListener(fallbackExecution = true)。
十、總結(jié)
基于事件驅(qū)動(dòng)模型可以很方便的實(shí)現(xiàn)解耦,提高代碼的可讀性和可維護(hù)性,代碼地址:https://github.com/2YSP/application-event-demo
疑問(wèn): 泛型支持那里如果不寫一個(gè)類繼承通用泛型事件,就跑不通這是為什么呢?
如果有人知道請(qǐng)告訴我,非常感謝。
參考:https://blog.csdn.net/sun_shaoping/article/details/84067446
轉(zhuǎn)載于:https://www.cnblogs.com/2YSP/p/10958230.html
總結(jié)
以上是生活随笔為你收集整理的Spring事件机制详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 判断两线段是否相交——快速排斥与跨立实验
- 下一篇: 第二阶段 铁大Facebook——十天冲