日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring事件机制详解

發(fā)布時(shí)間:2024/9/5 javascript 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring事件机制详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、前言

??說(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):

  • 首先是一種對(duì)象間的一對(duì)多的關(guān)系;最簡(jiǎn)單的如交通信號(hào)燈,信號(hào)燈是目標(biāo)(一方),行人注視著信號(hào)燈(多方)。
  • 當(dāng)目標(biāo)發(fā)送改變(發(fā)布),觀察者(訂閱者)就可以接收到改變。
  • 觀察者如何處理(如行人如何走,是快走/慢走/不走,目標(biāo)不會(huì)管的),目標(biāo)無(wú)需干涉;所以就松散耦合了它們之間的關(guān)系。
  • Java API實(shí)現(xiàn)和自定義實(shí)現(xiàn)觀察者模式:

    Java提供了兩個(gè)接口java.util.Observablejava.util.Observer,代碼可參考https://github.com/2YSP/design-pattern/tree/master/src/cn/sp/observer

    三、Spring類圖分析

    ?


    類圖

    ?

    事件

  • ApplicationEvent 繼承自 JDK 的 EventObject,JDK要求所有事件將繼承它,并通過(guò)source得到事件源,比如AWT事件體系也是繼承它。
  • 系統(tǒng)默認(rèn)提供了如下ApplicationEvent事件實(shí)現(xiàn):
  • ?


    類圖

    ?

    事件發(fā)布者

    具體代表者是:ApplicationEventPublisherApplicationEventMulticaster,系統(tǒng)默認(rèn)提供了如下實(shí)現(xiàn):

    ?


    ApplicationEventPublisher類圖

    ?

    ?


    ApplicationEventMulticaster類圖

    ?

  • ApplicationContext 接口繼承了 ApplicationEventPublisher,并在 AbstractApplicationContext 實(shí)現(xiàn)了具體代碼,實(shí)際執(zhí)行是委托給ApplicationEventMulticaster(可以認(rèn)為是多播)
    代碼如下:
  • ?


    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í)體類:

    public class Order {private String orderNo;private String orderStatus;private String goods;private Date createTime;//省略get、set、toString方法 }

    訂單創(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

  • @Service?
  • public class OrderService implements ApplicationEventPublisherAware {?
  • ?
  • private ApplicationEventPublisher applicationEventPublisher;?
  • ?
  • /**?
  • * 訂單保存?
  • */?
  • public void save(){?
  • String orderNo = getOrderNo();?
  • Order order = new Order();?
  • order.setOrderNo(orderNo);?
  • order.setOrderStatus("待付款");?
  • order.setCreateTime(new Date());?
  • order.setGoods("手機(jī)");?
  • System.out.println("訂單保存成功:" + order.toString());?
  • ?
  • //發(fā)布事件?
  • applicationEventPublisher.publishEvent(new OrderCreateEvent(this,order));?
  • System.out.println("================");?
  • ?
  • }?
  • ?
  • private String getOrderNo() {?
  • String millis = String.valueOf(System.currentTimeMillis());?
  • String str = millis.substring(millis.length() - 7, millis.length() - 1);?
  • return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + str;?
  • }?
  • ?
  • ?
  • @Override?
  • public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {?
  • this.applicationEventPublisher = applicationEventPublisher;?
  • }?
  • }?
  • 監(jiān)聽(tīng)器OrderCreateEventListener

  • @Component?
  • public class OrderCreateEventListener implements ApplicationListener<OrderCreateEvent> {?
  • ?
  • ?
  • @Override?
  • public void onApplicationEvent(OrderCreateEvent event) {?
  • System.out.printf(this.getClass().getName()+ " -- ApplicationListener 接口實(shí)現(xiàn),訂單號(hào)[%s]:,鎖定商品[%s]\n",?
  • event.getOrder().getOrderNo(), event.getOrder().getGoods());?
  • }?
  • }?
  • 運(yùn)行測(cè)試類:

    @RunWith(SpringRunner.class) @SpringBootTest public class ApplicationEventDemoApplicationTests {@AutowiredOrderService orderService;@Testpublic 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,使用示例如下:

    @Component public class OrderCreateEventListenerAnnotation {@EventListenerpublic 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ā)的,如果想異步的怎么辦?
    只需要兩步:

  • 啟動(dòng)類上添加 @EnableAsync注解,開(kāi)啟異步支持。
  • 監(jiān)聽(tīng)方法上添加 @Async注解
  • @Async@EventListenerpublic void createOrderEvent(OrderCreateEvent event){System.out.println(this.getClass().getName()+"--訂單創(chuàng)建事件,@EventListener注解實(shí)現(xiàn),orderNo:"+event.getOrder().getOrderNo());}

    七、泛型支持

    事件類一定要繼承ApplicationEvent嗎?
    當(dāng)然不是,我們還可以自定義泛型類實(shí)現(xiàn)事件調(diào)度(這個(gè)是我認(rèn)為最厲害的地方了)。

  • 寫個(gè)通用泛型類事件
  • /*** 可以自定義泛型類實(shí)現(xiàn)事件調(diào)度* Created by 2YSP on 2019/5/30.*/ public class GenericEvent<T> {private T data;private boolean success;public GenericEvent(T data,boolean success){this.data = data;this.success = success;}public T getData() {return data;}public void setData(T data) {this.data = data;}public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;} }
  • 寫個(gè)具體類型的事件
  • public class OrderGenericEvent extends GenericEvent<Order> {public OrderGenericEvent(Order data, boolean success) {super(data, success);} }
  • 在OrderService的save()方法中發(fā)布事件
  • applicationEventPublisher.publishEvent(new OrderGenericEvent(order,true));

  • 事件處理
  • @Component public class OrderGenericEventListener {@EventListener(condition = "#event.success")public void orderListener(GenericEvent<Order> event){System.out.println(this.getClass().getName()+"--處理泛型條件事件。。。");} }

    測(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ì)象。
    示例代碼:

    public void save(){String orderNo = getOrderNo();Order order = new Order();order.setOrderNo(orderNo);order.setOrderStatus("待付款");order.setCreateTime(new Date());order.setGoods("手機(jī)");System.out.println("訂單保存成功:" + order.toString());//發(fā)布事件 // applicationEventPublisher.publishEvent(new OrderCreateEvent(this,order));applicationEventPublisher.publishEvent(order); // applicationEventPublisher.publishEvent(new OrderGenericEvent(order,true));System.out.println("================");}

    訂單監(jiān)聽(tīng)器

    @Component public class OrderListener {@EventListenerpublic void orderListener(Order order){System.out.println(this.getClass().getName() + " -- 監(jiān)聽(tīng)一個(gè)訂單");}@EventListenerpublic 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ù)階段:

  • AFTER_COMMIT(默認(rèn)的):在事務(wù)成功后觸發(fā)
  • AFTER_ROLLBACK:事務(wù)回滾時(shí)觸發(fā)
  • AFTER_COMPLETION:事務(wù)完成后觸發(fā),不論是否成功
  • BEFORE_COMMIT:事務(wù)提交之前觸發(fā)
  • @TransactionalEventListener(phase = BEFORE_COMMIT) public void txEvent(Order order) {System.out.println("事物監(jiān)聽(tīng)"); }

    上面代碼的意思是僅當(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)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。