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

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

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

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

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

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

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

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

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

Java: 17
Spring Boot: 3.5.5
Spring Framework: 6.2.10

1 Spring Event 如何使用?

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

1.1 定義事件(Event)

自 Spring 4.2 后,定義事件時(shí),無需再繼承 ApplicationEvent。任何一個(gè)普通的 Java POJO 都可以充當(dāng)事件實(shí)體類。

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

package com.example.demo.model;

@Builder
@Data
public class UserRegisteredEvent {

    private String email;
    private String username;
}

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

下面即是事件發(fā)布者 UserServiceImpl 在保存 User 后,調(diào)用 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ā)布了一個(gè) UserRegisteredEvent,并打印了一段事件成功發(fā)布的日志。

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

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

一個(gè)事件可以被多個(gè)訂閱者監(jiān)聽,下面的郵件服務(wù)、優(yōu)惠券服務(wù)監(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());
    }
}

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

1.4 測(cè)試(Testing)

下面為 UserService 編寫一個(gè)單元測(cè)試類 UserServiceTest 來測(cè)試事件的發(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);
    }
}

運(yùn)行 UserServiceTest 測(cè)試類,可以看到,UserServicesave() 方法被調(diào)用后,控制臺(tái)打印了如下三行日志:

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 默認(rèn)是同步執(zhí)行的,即 ApplicationEventPublisherpublishEvent() 方法是阻塞式的,會(huì)等待所有監(jiān)聽器將事件處理完畢才算調(diào)用結(jié)束。

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

2 Spring Event 進(jìn)階用法

若想讓監(jiān)聽器的執(zhí)行變成異步的,可以在程序啟動(dòng)類上加上 @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());
    }
}

再次運(yùn)行 UserServiceTest 測(cè)試類,發(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ā)布者在主線程調(diào)用 publishEvent() 方法后立即返回,而監(jiān)聽器的邏輯處理會(huì)在新啟動(dòng)的線程中執(zhí)行,不會(huì)再阻塞主線程。

3 小結(jié)

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

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

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

相關(guān)文章

  • logback FixedWindowRollingPolicy固定窗口算法重命名文件滾動(dòng)策略

    logback FixedWindowRollingPolicy固定窗口算法重命名文件滾動(dòng)策略

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

    Spring復(fù)雜對(duì)象創(chuàng)建的方式小結(jié)

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

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

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

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

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

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

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

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

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

    Java中的Optional類詳細(xì)解讀

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

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

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

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

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

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

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

最新評(píng)論

建始县| 林州市| 林口县| 施甸县| 五原县| 珲春市| 高密市| 桓仁| 浮山县| 玉屏| 松江区| 巴林左旗| 宝兴县| 宿松县| 垫江县| 错那县| 宣威市| 黔东| 阜城县| 金川县| 乡宁县| 成安县| 鄂州市| 泰州市| 兖州市| 顺昌县| 皮山县| 西昌市| 海口市| 舒城县| 临夏县| 贵州省| 西乌珠穆沁旗| 惠州市| 利辛县| 榆树市| 长顺县| 沙河市| 五莲县| 澄城县| 闽清县|