日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

使用上 Spring 的事件機制,真香!

來源: 責編: 時間:2023-09-18 21:41:51 428觀看
導讀本文主要是簡單的講述了Spring的事件機制,基本概念,講述了事件機制的三要素事件、事件發布、事件監聽器。如何實現一個事件機制,應用的場景,搭配@Async注解實現異步的操作等等。希望對大家有所幫助。Spring的事件機制的基

本文主要是簡單的講述了Spring的事件機制,基本概念,講述了事件機制的三要素事件、事件發布、事件監聽器。如何實現一個事件機制,應用的場景,搭配@Async注解實現異步的操作等等。希望對大家有所幫助。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

Spring的事件機制的基本概念

Spring的事件機制是Spring框架中的一個重要特性,基于觀察者模式實現,它可以實現應用程序中的解耦,提高代碼的可維護性和可擴展性。Spring的事件機制包括事件、事件發布、事件監聽器等幾個基本概念。其中,事件是一個抽象的概念,它代表著應用程序中的某個動作或狀態的發生。事件發布是事件發生的地方,它負責產生事件并通知事件監聽器。事件監聽器是事件的接收者,它負責處理事件并執行相應的操作。在Spring的事件機制中,事件源和事件監聽器之間通過事件進行通信,從而實現了模塊之間的解耦。vWW28資訊網——每日最新資訊28at.com

舉個例子:用戶修改密碼,修改完密碼后需要短信通知用戶,記錄關鍵性日志,等等其他業務操作。vWW28資訊網——每日最新資訊28at.com

如下圖,就是我們需要調用多個服務來進行實現一個修改密碼的功能。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 使用了事件機制后,我們只需要發布一個事件,無需關心其擴展的邏輯,讓我們的事件監聽器去處理,從而實現了模塊之間的解耦。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 事件

通過繼承ApplicationEvent,實現自定義事件。是對 Java EventObject 的擴展,表示 Spring 的事件,Spring 中的所有事件都要基于其進行擴展。其源碼如下。vWW28資訊網——每日最新資訊28at.com

我們可以獲取到timestamp屬性指的是發生時間。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 事件發布

vWW28資訊網——每日最新資訊28at.com

事件發布是事件發生的地方,它負責產生事件并通知事件監聽器。ApplicationEventPublisher用于用于發布 ApplicationEvent 事件,發布后 ApplicationListener 才能監聽到事件進行處理。源碼如下。vWW28資訊網——每日最新資訊28at.com

需要一個ApplicationEvent,就是我們的事件,來進行發布事件。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 事件監聽器

ApplicationListener 是 Spring 事件的監聽器,用來接受事件,所有的監聽器都必須實現該接口。該接口源碼如下。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 Spring的事件機制的使用方法

vWW28資訊網——每日最新資訊28at.com

下面會給大家演示如何去使用Spring的事件機制。就拿修改密碼作為演示。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

如何定義一個事件

新增一個類,繼承我們的ApplicationEvent。vWW28資訊網——每日最新資訊28at.com

如下面代碼,繼承后定義了一個userId,有一個UserChangePasswordEvent方法。這里就定義我們監聽器需要的業務參數,監聽器需要那些參數,我們這里就定義那些參數。vWW28資訊網——每日最新資訊28at.com

/** * @Author JiaQIng * @Description 修改密碼事件 * @ClassName UserChangePasswordEvent * @Date 2023/3/26 13:55 **/@Getter@Setterpublic class UserChangePasswordEvent extends ApplicationEvent {    private String userId;    public UserChangePasswordEvent(String userId) {        super(new Object());        this.userId = userId;    }}

vWW28資訊網——每日最新資訊28at.com

如何監聽事件

實現監聽器有兩種方法:vWW28資訊網——每日最新資訊28at.com

(1) 新建一個類實現ApplicationListener接口,并且重寫onApplicationEvent方法注入到Spring容器中,交給Spring管理如下代碼新建了一個發送短信監聽器,收到事件后執行業務操作****;vWW28資訊網——每日最新資訊28at.com

/** * @Author JiaQIng * @Description 發送短信監聽器 * @ClassName MessageListener * @Date 2023/3/26 14:16 **/@Componentpublic class MessageListener implements ApplicationListener<UserChangePasswordEvent> {    @Override    public void onApplicationEvent(UserChangePasswordEvent event) {        System.out.println("收到事件:" + event);        System.out.println("開始執行業務操作給用戶發送短信。用戶userId為:" + event.getUserId());    }}

(2) 使用@EventListener注解標注處理事件的方法,此時Spring將創建一個ApplicationListenerbean對象,使用給定的方法處理事件源碼如下參數可以給指定的事件這里巧妙的用到了@AliasFor的能力,放到了@EventListener身上注意:一般建議都需要指定此值,否則默認可以處理所有類型的事件,范圍太廣了;vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 代碼如下。新建一個事件監聽器,注入到Spring容器中,交給Spring管理。在指定方法上添加@EventListener參數為監聽的事件。方法為業務代碼。使用 @EventListener 注解的好處是一個類可以寫很多監聽器,定向監聽不同的事件,或者同一個事件。vWW28資訊網——每日最新資訊28at.com

/** * @Author JiaQIng * @Description 事件監聽器 * @ClassName LogListener * @Date 2023/3/26 14:22 **/@Componentpublic class ListenerEvent {    @EventListener({ UserChangePasswordEvent.class })    public void LogListener(UserChangePasswordEvent event) {        System.out.println("收到事件:" + event);        System.out.println("開始執行業務操作生成關鍵日志。用戶userId為:" + event.getUserId());    }    @EventListener({ UserChangePasswordEvent.class })    public void messageListener(UserChangePasswordEvent event) {        System.out.println("收到事件:" + event);        System.out.println("開始執行業務操作給用戶發送短信。用戶userId為:" + event.getUserId());    }}

(3)  @TransactionalEventListener來定義一個監聽器,他與@EventListener不同的就是@EventListener標記一個方法作為監聽器,他默認是同步執行,如果發布事件的方法處于事務中,那么事務會在監聽器方法執行完畢之后才提交事件發布之后就由監聽器去處理,而不要影響原有的事務,也就是說希望事務及時提交我們就可以使用該注解來標識注意此注解需要spring-tx的依賴;vWW28資訊網——每日最新資訊28at.com

注解源碼如下:主要是看一下注釋內容。vWW28資訊網——每日最新資訊28at.com

// 在這個注解上面有一個注解:@EventListener,所以表明其實這個注解也是個事件監聽器。 @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@EventListenerpublic @interface TransactionalEventListener { /**  * 這個注解取值有:BEFORE_COMMIT(指定目標方法在事務commit之前執行)、AFTER_COMMIT(指定目標方法在事務commit之后執行)、  * AFTER_ROLLBACK(指定目標方法在事務rollback之后執行)、AFTER_COMPLETION(指定目標方法在事務完成時執行,這里的完成是指無論事務是成功提交還是事務回滾了)  * 各個值都代表什么意思表達什么功能,非常清晰,  * 需要注意的是:AFTER_COMMIT + AFTER_COMPLETION是可以同時生效的  * AFTER_ROLLBACK + AFTER_COMPLETION是可以同時生效的  */ TransactionPhase phase() default TransactionPhase.AFTER_COMMIT; /**  * 表明若沒有事務的時候,對應的event是否需要執行,默認值為false表示,沒事務就不執行了。  */ boolean fallbackExecution() default false; /**  *  這里巧妙的用到了@AliasFor的能力,放到了@EventListener身上  *  注意:一般建議都需要指定此值,否則默認可以處理所有類型的事件,范圍太廣了。  */ @AliasFor(annotation = EventListener.class, attribute = "classes") Class<?>[] value() default {}; /**  * The event classes that this listener handles.  * <p>If this attribute is specified with a single value, the annotated  * method may optionally accept a single parameter. However, if this  * attribute is specified with multiple values, the annotated method  * must <em>not</em> declare any parameters.  */ @AliasFor(annotation = EventListener.class, attribute = "classes") Class<?>[] classes() default {}; /**  * Spring Expression Language (SpEL) attribute used for making the event  * handling conditional.  * <p>The default is {@code ""}, meaning the event is always handled.  * @see EventListener#condition  */ @AliasFor(annotation = EventListener.class, attribute = "condition") String condition() default ""; /**  * An optional identifier for the listener, defaulting to the fully-qualified  * signature of the declaring method (e.g. "mypackage.MyClass.myMethod()").  * @since 5.3  * @see EventListener#id  * @see TransactionalApplicationListener#getListenerId()  */ @AliasFor(annotation = EventListener.class, attribute = "id") String id() default "";}

使用方式如下。phase事務類型,value指定事件。vWW28資訊網——每日最新資訊28at.com

/** * @Author JiaQIng * @Description 事件監聽器 * @ClassName LogListener * @Date 2023/3/26 14:22 **/@Componentpublic class ListenerEvent {    @EventListener({ UserChangePasswordEvent.class })    public void logListener(UserChangePasswordEvent event) {        System.out.println("收到事件:" + event);        System.out.println("開始執行業務操作生成關鍵日志。用戶userId為:" + event.getUserId());    }    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,value = { UserChangePasswordEvent.class })    public void messageListener(UserChangePasswordEvent event) {        System.out.println("收到事件:" + event);        System.out.println("開始執行業務操作給用戶發送短信。用戶userId為:" + event.getUserId());    }}

vWW28資訊網——每日最新資訊28at.com

如何發布一個事件

(1) 使用ApplicationContext進行發布,由于ApplicationContext已經繼承了ApplicationEventPublisher,因此可以直接使用發布事件源碼如下;vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 (2) 直接注入我們的ApplicationEventPublisher,使用@Autowired注入一下;vWW28資訊網——每日最新資訊28at.com

三種發布事件的方法,我給大家演示一下@Autowired注入的方式發布我們的事件。vWW28資訊網——每日最新資訊28at.com

@SpringBootTestclass SpirngEventApplicationTests {    @Autowired    ApplicationEventPublisher appEventPublisher;    @Test    void contextLoads() {        appEventPublisher.publishEvent(new UserChangePasswordEvent("1111111"));    }}

我們執行一下看一下接口:vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 測試成功。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

搭配@Async注解實現異步操作

監聽器默認是同步執行的,如果我們想實現異步執行,可以搭配@Async注解使用,但是前提條件是你真的懂@Async注解,使用不當會出現問題的。 后續我會出一篇有關@Async注解使用的文章。這里就不給大家詳細的解釋了。有想了解的同學可以去網上學習一下有關@Async注解使用。vWW28資訊網——每日最新資訊28at.com

使用@Async時,需要配置線程池,否則用的還是默認的線程池也就是主線程池,線程池使用不當會浪費資源,嚴重的會出現OOM事故。vWW28資訊網——每日最新資訊28at.com

下圖是阿里巴巴開發手冊的強制要求。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

 簡單的演示一下:這里聲明一下俺沒有使用線程池,只是簡單的演示一下。vWW28資訊網——每日最新資訊28at.com

(1) 在我們的啟動類上添加@EnableAsync開啟異步執行配置;vWW28資訊網——每日最新資訊28at.com

@EnableAsync@SpringBootApplicationpublic class SpirngEventApplication {    public static void main(String[] args) {        SpringApplication.run(SpirngEventApplication.class, args);    }}

(2) 在我們想要異步執行的監聽器上添加@Async注解:vWW28資訊網——每日最新資訊28at.com

/** * @Author JiaQIng * @Description 事件監聽器 * @ClassName LogListener * @Date 2023/3/26 14:22 **/@Componentpublic class ListenerEvent {        @Async    @EventListener({ UserChangePasswordEvent.class })    public void logListener(UserChangePasswordEvent event) {        System.out.println("收到事件:" + event);        System.out.println("開始執行業務操作生成關鍵日志。用戶userId為:" + event.getUserId());    }}

這樣我們的異步執行監聽器的業務操作就完成了。vWW28資訊網——每日最新資訊28at.com

vWW28資訊網——每日最新資訊28at.com

Spring的事件機制的應用場景

  • 告警操作,比喻釘釘告警,異常告警,可以通過事件機制進行解耦;
  • 關鍵性日志記錄和業務埋點,比喻說我們的關鍵日志需要入庫,記錄一下操作時間,操作人,變更內容等等,可以通過事件機制進行解耦;
  • 性能監控,比喻說一些接口的時長,性能方便的埋點等可以通過事件機制進行解耦;
  • 一切與主業務無關的操作都可以通過這種方式進行解耦,常用的場景大概就上述提到的,而且很多架構的源碼都有使用這種機制,如GateWay,Spring等等;

vWW28資訊網——每日最新資訊28at.com

Spring的事件機制的注意事項

  • 對于同一個事件,有多個監聽器的時候,注意可以通過@Order注解指定順序,Order的value值越小,執行的優先級就越高;
  • 如果發布事件的方法處于事務中,那么事務會在監聽器方法執行完畢之后才提交事件發布之后就由監聽器去處理,而不要影響原有的事務,也就是說希望事務及時提交我們就可以@TransactionalEventListener來定義一個監聽器;
  • 監聽器默認是同步執行的,如果我們想實現異步執行,可以搭配@Async注解使用,但是前提條件是你真的懂@Async注解,使用不當會出現問題的;
  • 對于同一個事件,有多個監聽器的時候,如果出現了異常,后續的監聽器就失效了,因為他是把同一個事件的監聽器add在一個集合里面循環執行,如果出現異常,需要注意捕獲異常處理異常;

本文鏈接:http://m.www897cc.com/showinfo-26-10471-0.html使用上 Spring 的事件機制,真香!

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 拋磚引玉:Redis 與 接口自動化測試框架的結合

下一篇: Python應知小技巧:如何用更少的代碼做更多的事情

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
午夜精品久久久久久久男人的天堂 | 亚洲国产欧美一区二区三区久久| 一区二区在线视频播放| 韩国av一区二区三区| 亚洲福利av| 一区二区三区欧美亚洲| 亚洲男人av电影| 久久久综合精品| 欧美日韩亚洲一区二区三区在线观看| 国产精品v欧美精品v日本精品动漫 | 一区视频在线| 亚洲人成在线观看| 亚洲欧美日韩国产一区二区| 久久久噜噜噜| 欧美另类在线播放| 国产伦精品一区二区三区免费迷 | 亚洲最黄网站| 久久久www免费人成黑人精品 | 欧美精品一区二区蜜臀亚洲| 国产精品系列在线播放| 在线免费观看日本欧美| 亚洲视频香蕉人妖| 久久综合狠狠综合久久综合88| 欧美乱妇高清无乱码| 国产一区二区三区在线免费观看| 亚洲国内高清视频| 羞羞答答国产精品www一本| 欧美精品 国产精品| 国产农村妇女毛片精品久久莱园子| 亚洲电影视频在线| 午夜精品久久久久久久99黑人| 国产精品成人免费视频| 国产亚洲一区二区三区| 亚洲精品国精品久久99热| 欧美一区二区三区另类 | 欧美先锋影音| 亚洲国产成人精品女人久久久 | 国产女人水真多18毛片18精品视频| 亚洲国产精品高清久久久| 亚洲欧美综合| 欧美日本韩国一区二区三区| 黄色成人精品网站| 亚洲你懂的在线视频| 欧美精品久久久久久久| 激情婷婷亚洲| 欧美一级片一区| 欧美午夜久久久| 亚洲精品永久免费| 久久综合九九| 国产午夜精品全部视频在线播放 | 国产欧美日韩精品在线| 一本久久a久久精品亚洲| 噜噜爱69成人精品| 国产专区综合网| 亚洲欧美激情四射在线日| 欧美日本亚洲视频| 亚洲高清毛片| 久久久91精品国产一区二区三区 | 亚洲国产经典视频| 久久免费国产精品1| 国产欧美一级| 亚洲天堂成人在线视频| 欧美精品三级| 亚洲激情视频在线播放| 久久网站热最新地址| 国产一区二区三区久久悠悠色av| 亚洲永久免费| 欧美性猛交xxxx乱大交蜜桃 | 欧美专区亚洲专区| 国产精品羞羞答答xxdd| 亚洲一区二区三区777| 欧美日韩一卡| 日韩午夜激情电影| 欧美日本高清| 日韩亚洲欧美精品| 欧美日本韩国| 99精品国产在热久久| 欧美激情精品久久久久久蜜臀| 亚洲国产高清在线| 免费在线亚洲欧美| 亚洲三级电影在线观看| 欧美国产日韩亚洲一区| 亚洲国产天堂久久综合网| 牛牛国产精品| 亚洲黄色在线| 欧美美女操人视频| 99精品99| 欧美性猛交xxxx免费看久久久| 一区二区三区欧美激情| 国产精品v一区二区三区 | 久久综合婷婷| 亚洲国产一区二区三区青草影视| 欧美freesex8一10精品| 亚洲黄网站在线观看| 欧美成人综合| 99在线热播精品免费| 欧美日韩午夜剧场| 亚洲男人天堂2024| 国产综合av| 美女日韩欧美| 亚洲三级性片| 国产精品jizz在线观看美国 | 久久久一二三| 亚洲国产日韩欧美一区二区三区| 欧美国产欧美亚洲国产日韩mv天天看完整 | 国产亚洲欧美日韩一区二区| 久久精品国产清高在天天线| 伊人狠狠色丁香综合尤物| 免费人成网站在线观看欧美高清| 亚洲人成小说网站色在线| 欧美日在线观看| 欧美一区三区三区高中清蜜桃| 狠狠狠色丁香婷婷综合激情| 免费不卡视频| 一区二区三区四区国产| 国产欧美日韩中文字幕在线| 浪潮色综合久久天堂| 99国产精品久久久| 国产日产亚洲精品| 免费成人网www| 在线一区二区日韩| 国内精品免费午夜毛片| 欧美激情va永久在线播放| 亚洲调教视频在线观看| 国产综合久久久久久鬼色| 欧美不卡福利| 亚洲欧美欧美一区二区三区| 玉米视频成人免费看| 欧美日韩在线免费| 久久精品综合网| 99国内精品久久| 黑人巨大精品欧美一区二区小视频| 欧美激情四色 | 久久免费少妇高潮久久精品99| 亚洲美女视频在线观看| 国产日韩高清一区二区三区在线| 噜噜噜噜噜久久久久久91| 亚洲天堂成人| 亚洲成在人线av| 国产精品入口日韩视频大尺度| 老色批av在线精品| 亚洲性夜色噜噜噜7777| 狠狠色狠色综合曰曰| 欧美日韩直播| 久久综合中文| 亚洲欧美不卡| 亚洲精品乱码久久久久久| 国产午夜精品理论片a级大结局| 欧美猛交免费看| 久久一综合视频| 亚洲欧美99| 亚洲日本免费| 韩国av一区| 国产精品视频网址| 欧美精品在线观看播放| 久久久亚洲精品一区二区三区 | 亚洲午夜久久久久久久久电影院 | 欧美在线中文字幕| av成人动漫| 亚洲国产精品嫩草影院| 国产精品视频内| 欧美精品激情在线观看| 久久综合久色欧美综合狠狠| 亚洲自拍偷拍网址| 亚洲伦理在线观看| 狠狠噜噜久久| 国产精品―色哟哟| 欧美日韩国产三区| 农夫在线精品视频免费观看| 久久精品国产亚洲精品| 亚洲一区精品视频| 亚洲伦伦在线| 亚洲春色另类小说| 国内成+人亚洲| 国产欧美日韩在线观看| 国产精品久久网| 欧美日韩视频专区在线播放| 欧美成人高清视频| 久久频这里精品99香蕉| 欧美一区二区三区免费在线看| 亚洲午夜高清视频| 亚洲另类在线一区| 亚洲国产精品v| 影音先锋在线一区| 国产一区二区三区免费在线观看| 欧美午夜免费电影| 欧美日韩亚洲一区二| 欧美日韩八区| 欧美精品一区二区三区很污很色的| 久热综合在线亚洲精品| 久久久噜噜噜久久久| 久久精品二区| 亚洲女性裸体视频| 亚洲欧美电影院| 亚洲欧美激情诱惑| 亚洲欧美成人一区二区三区| 亚洲午夜一区二区三区| 一本色道久久综合亚洲91| 亚洲另类黄色| 亚洲剧情一区二区| 99在线|亚洲一区二区| 一本色道久久99精品综合| 99国产成+人+综合+亚洲欧美| 日韩视频在线观看一区二区|