最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Spring Event實現(xiàn)內部模塊間的輕松解耦

 更新時間:2025年08月28日 08:51:52   作者:磊磊落落  
Spring Event 是 Spring 框架提供的一個核心組件,其允許服務內部不同模塊之間通過觀察者模式(發(fā)布-訂閱模式)進行通信,從而實現(xiàn)模塊間的解耦,本文給大家介紹了如何使用 Spring Event 實現(xiàn)內部模塊間的輕松解耦,需要的朋友可以參考下

Spring Event 是 Spring 框架提供的一個核心組件,其允許服務內部不同模塊之間通過觀察者模式(發(fā)布-訂閱模式)進行通信,從而實現(xiàn)模塊間的解耦。

即 Spring Event 是一種事件驅動的編程模型,一個模塊在做完一件事后,無需直接調用其它模塊處理后續(xù)邏輯,而是發(fā)布一個事件出來,由其它對該事件感興趣的模塊訂閱并處理這個事件,事件發(fā)布者無需關注訂閱者是誰,從而實現(xiàn)模塊間的輕松解耦。

Spring Event 的使用非常的廣泛,包含但不限于:用戶注冊成功后的后續(xù)操作(如發(fā)送歡迎郵件、發(fā)放新用戶優(yōu)惠券、初始化積分等);訂單狀態(tài)的變更通知(訂單支付成功后通知庫存系統(tǒng)減庫存、通知物流系統(tǒng)準備發(fā)貨等);系統(tǒng)日志記錄(重要數(shù)據(jù)被修改后通知日志系統(tǒng)記錄變更字段、通知管理員進行安全檢查和審計等)。

除了上述業(yè)務場景外,Spring Event 有時還能很巧妙的解決一些技術問題:比如解決 Spring 父子模塊的通信。實際項目中,Spring Boot 工程通常會依賴一個 SharedModule 父模塊,這個 SharedModule 父模塊里擁有一些公共的 POJO 類、數(shù)據(jù)庫 Entity 類、Util 類等,如果想在父模塊里調用子模塊的方法來實現(xiàn)一些邏輯,在技術上是有一點難度的。但通過借助 Spring Event,父模塊只需增加一個事件,然后發(fā)布即可,在子模塊中監(jiān)聽并處理就好了。

介紹了 Spring Event 是什么以及其適用的場景外。本文將以「用戶注冊成功后發(fā)送郵件、發(fā)放優(yōu)惠券」為例,創(chuàng)建一個 Spring Boot 示例程序,來演示 Spring Event 的使用。

下面列出寫作本文時用到的 Java、Spring Boot 以及 Spring 框架的版本:

Java: 17
Spring Boot: 3.5.5
Spring Framework: 6.2.10

1 Spring Event 如何使用?

如何使用 Spring Event 呢?只有三個步驟:定義事件、發(fā)布事件、監(jiān)聽事件。

1.1 定義事件(Event)

自 Spring 4.2 后,定義事件時,無需再繼承 ApplicationEvent。任何一個普通的 Java POJO 都可以充當事件實體類。

下面即是我們定義的用戶注冊后事件:

package com.example.demo.model;

@Builder
@Data
public class UserRegisteredEvent {

    private String email;
    private String username;
}

1.2 發(fā)布事件(Event Publisher)

下面即是事件發(fā)布者 UserServiceImpl 在保存 User 后,調用 ApplicationEventPublisher 發(fā)布 UserRegisteredEvent 的代碼:

package com.example.demo.service.impl;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    public void save(User user) {
        // save user
        // userRepository.save(user);

        // publish event
        UserRegisteredEvent event = UserRegisteredEvent.builder()
                .email(user.getEmail())
                .username(user.getUsername())
                .build();

        eventPublisher.publishEvent(event);

        LOGGER.info("user registered event successfully published");
    }
}

可以看到,上述代碼在 save User 后,發(fā)布了一個 UserRegisteredEvent,并打印了一段事件成功發(fā)布的日志。

1.3 監(jiān)聽事件 (Event Listener)

自 Spring 4.2 后,訂閱者要想監(jiān)聽事件,無需再實現(xiàn) ApplicationListener 接口,而只需添加一個接收 Event 對象的方法,并在方法上加上 @EventListener 注解即可。

一個事件可以被多個訂閱者監(jiān)聽,下面的郵件服務、優(yōu)惠券服務監(jiān)聽了 UserRegisteredEvent

package com.example.demo.service.impl;

@Service
public class EmailServiceImpl implements EmailService {

    @EventListener
    public void handleUserRegisteredEvent(UserRegisteredEvent event) {
        // send email
        LOGGER.info("email successfully sent to: {}", event.getEmail());
    }
}
package com.example.demo.service.impl;

@Service
public class CouponServiceImpl implements CouponService {

    @EventListener
    public void handleUserRegisteredEvent(UserRegisteredEvent event) {
        // issue coupon
        LOGGER.info("coupon successfully issued to: {}", event.getEmail());
    }
}

可以看到,上述兩個 Service 實現(xiàn)類在接收到 UserRegisteredEvent 后,分別打印了一段日志來模擬郵件成功發(fā)送和優(yōu)惠券成功發(fā)放。

1.4 測試(Testing)

下面為 UserService 編寫一個單元測試類 UserServiceTest 來測試事件的發(fā)布和訂閱:

package com.example.demo;

@SpringBootTest
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testSave() {
        User user = new User();
        // user.setXxx();

        userService.save(user);
    }
}

運行 UserServiceTest 測試類,可以看到,UserServicesave() 方法被調用后,控制臺打印了如下三行日志:

CouponServiceImpl  : coupon successfully issued to: larry@larry.com
EmailServiceImpl   : email successfully sent to: larry@larry.com
UserServiceImpl    : user registered event successfully published

說明我們編寫的 UserRegisteredEvent 被成功發(fā)布、訂閱和處理了。

但需要注意上面日志的打印順序:事件被處理的日志打印后才打印了事件發(fā)布的日志,這說明 Spring Event 默認是同步執(zhí)行的,即 ApplicationEventPublisherpublishEvent() 方法是阻塞式的,會等待所有監(jiān)聽器將事件處理完畢才算調用結束。

這樣,若訂閱者的處理邏輯很耗時的話會影響到發(fā)布者的性能。所以,是否有方法讓監(jiān)聽器的處理變成異步的呢?下面請看 Spring Event 的進階用法。

2 Spring Event 進階用法

若想讓監(jiān)聽器的執(zhí)行變成異步的,可以在程序啟動類上加上 @EnableAsync 注解:

package com.example.demo;

@EnableAsync
@SpringBootApplication
public class DemoApplication {
}

然后在事件處理方法上加上 @Async 注解,即能使事件處理方法變成異步執(zhí)行。

package com.example.demo.service.impl;

@Service
public class EmailServiceImpl implements EmailService {

    @Async
    @EventListener
    public void handleUserRegisteredEvent(UserRegisteredEvent event) {
        // send email
        LOGGER.info("email successfully sent to: {}", event.getEmail());
    }
}

再次運行 UserServiceTest 測試類,發(fā)現(xiàn)發(fā)布者與訂閱者的日志打印順序變成了:

UserServiceImpl    : user registered event successfully published
CouponServiceImpl  : coupon successfully issued to: larry@larry.com
EmailServiceImpl   : email successfully sent to: larry@larry.com

即說明事件發(fā)布者在主線程調用 publishEvent() 方法后立即返回,而監(jiān)聽器的邏輯處理會在新啟動的線程中執(zhí)行,不會再阻塞主線程。

3 小結

綜上,本文首先介紹了 Spring Event 的功能,然后以「用戶注冊成功后發(fā)送郵件、發(fā)放優(yōu)惠券」為例,用 Spring Boot 示例程序的方式演示了 Spring Event 的使用。

經過本文的實踐,說明借助 Spring Event 的確可以很輕松的實現(xiàn)服務內部模塊間的解耦。但若是服務間的通信和解耦,以及需要更高的并發(fā)和可靠性,則還是需要引入其它第三方消息隊列等工具來實現(xiàn)。

以上就是使用Spring Event實現(xiàn)內部模塊間的輕松解耦的詳細內容,更多關于Spring Event內部模塊間解耦的資料請關注腳本之家其它相關文章!

相關文章

  • logback FixedWindowRollingPolicy固定窗口算法重命名文件滾動策略

    logback FixedWindowRollingPolicy固定窗口算法重命名文件滾動策略

    這篇文章主要介紹了FixedWindowRollingPolicy根據(jù)logback 固定窗口算法重命名文件滾動策略源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Spring復雜對象創(chuàng)建的方式小結

    Spring復雜對象創(chuàng)建的方式小結

    這篇文章主要介紹了Spring復雜對象創(chuàng)建的三種方式,現(xiàn)在使用Spring如何創(chuàng)建這種類型的對象?Spring中提供了三種方法來創(chuàng)建復雜對象,需要的朋友可以參考下
    2022-01-01
  • 淺談mybatis 樂觀鎖實現(xiàn),解決并發(fā)問題

    淺談mybatis 樂觀鎖實現(xiàn),解決并發(fā)問題

    這篇文章主要介紹了淺談mybatis 樂觀鎖實現(xiàn),解決并發(fā)問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • mybatis-plus的多租戶不同版本實現(xiàn)的兩種方式

    mybatis-plus的多租戶不同版本實現(xiàn)的兩種方式

    本文主要介紹了mybatis-plus的多租戶不同版本實現(xiàn)的兩種方式,Mybatis Plus 3.4.0版本之后多租戶的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • 如何解決getReader() has already been called for this request問題

    如何解決getReader() has already been called&

    這篇文章主要介紹了如何解決getReader() has already been called for this request問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java線程的并發(fā)工具類實現(xiàn)原理解析

    Java線程的并發(fā)工具類實現(xiàn)原理解析

    本文給大家講解Java線程的并發(fā)工具類的一些知識,通過適用場景分析大數(shù)據(jù)量統(tǒng)計類任務的實現(xiàn)原理和封裝,多個示例代碼講解的非常詳細,對java線程并發(fā)工具類相關知識感興趣的朋友一起學習下吧
    2021-06-06
  • Java中的Optional類詳細解讀

    Java中的Optional類詳細解讀

    這篇文章主要介紹了Java中的Optional類詳細解讀,Optional是Java中的一個類,它的作用是用于解決空指針異常的問題,它提供了一些有用的方法,可以幫助我們避免顯式進行空值檢測,需要的朋友可以參考下
    2023-08-08
  • Java實現(xiàn)Html保存為.mhtml文件的代碼邏輯

    Java實現(xiàn)Html保存為.mhtml文件的代碼邏輯

    文章介紹了實現(xiàn)將HTML字符串保存為.mhtml文件的代碼邏輯,包括通過URL和Cookie免密獲取HTML字符串,將HTML中的圖片、CSS、JS轉換為base64字符串,刪除不需要的布局和內容,最終將替換后的HTML保存為.mhtml文件,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • 專屬于程序員的浪漫-Java輸出動態(tài)閃圖iloveyou

    專屬于程序員的浪漫-Java輸出動態(tài)閃圖iloveyou

    這篇文章主要介紹了專屬于程序員的浪漫-Java輸出動態(tài)閃圖iloveyou,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • IntelliJ IDEA創(chuàng)建maven多模塊項目(圖文教程)

    IntelliJ IDEA創(chuàng)建maven多模塊項目(圖文教程)

    這篇文章主要介紹了IntelliJ IDEA創(chuàng)建maven多模塊項目(圖文教程),非常具有實用價值,需要的朋友可以參考下
    2017-09-09

最新評論

盐亭县| 土默特左旗| 五指山市| 茶陵县| 宾川县| 拜泉县| 广水市| 文昌市| 巩义市| 新昌县| 通化市| 丹寨县| 六盘水市| 津市市| 砀山县| 清苑县| 吉隆县| 慈利县| 连云港市| 玉环县| 扬州市| 黄骅市| 安陆市| 平泉县| 昌乐县| 吴旗县| 齐齐哈尔市| 北宁市| 溆浦县| 吴忠市| 木兰县| 辰溪县| 岑巩县| 淮安市| 沂南县| 丁青县| 长治县| 宜丰县| 炉霍县| 平利县| 托克逊县|