欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringEvent優(yōu)雅解耦時連續(xù)兩個bug的解決方案

 更新時間:2022年12月12日 11:29:04   作者:程序員拾山  
這篇文章主要為大家介紹了SpringEvent優(yōu)雅解耦時連續(xù)兩個bug的解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1,基本原理

日常開發(fā)中,我們有時會使用SpringEvent對業(yè)務(wù)解耦,使我們的代碼更加高內(nèi)聚低耦合,不過如果對其運行原理不清楚,那么在使用的過程中,一不留神就會出現(xiàn)一些bug。

今天我們回顧一下SpringEvent使用的基本原理,需要優(yōu)化的點,以及非常常見的兩種錯誤。

Spring的事件模式其實很簡單,我們創(chuàng)建一個Event事件,當Event發(fā)生時,廣播器對事件進行發(fā)布,然后對應(yīng)的Listener進行處理即可。

Spring的事件一共有三個組件:

1,Event:用于定于我們的事件,比如ApplicationEvent或者通過繼承ApplicationEvent定義我們自己的事件。

2,廣播器Multicaster:當事件發(fā)生時,將事件廣播出去。

3,監(jiān)聽器Listener:監(jiān)聽和處理廣播器廣播的事件。

2,基本用法

第一步,首先定義一個Event事件,

@Getter
@Setter
public class MessageEvent extends ApplicationEvent {
    private String content;
    public MessageEvent(String content) {
        super(new Object());
        this.content = content;
    }
}

第二步,定義一個Listener對事件進行監(jiān)聽,

@Component
public class MessageListener {
    @EventListener
    public void listen(MessageEvent messageEvent) {
        System.out.println("收到消息:" + messageEvent.getContent());
    }
}

最后在我們的業(yè)務(wù)邏輯需要的地方,就可以發(fā)布事件了。

@RestController
@RequestMapping(value = "/demo")
public class DemoController {
    @Resource
    private ApplicationContext applicationContext;
    @PostMapping(value = "/send")
    public ResponseEntity sendMessage() {
        //.....
        //處理一些業(yè)務(wù)邏輯之后,發(fā)送通知消息
        MessageEvent messageEvent = new MessageEvent("發(fā)布一條測試消息");
        this.applicationContext.publishEvent(messageEvent);
        return ResponseEntity.ok().build();
    }
}

3,需要注意的點

一,對于同一個Event,我們可以定義多個Listener,多個Listener之間可以通過@Order來指定順序,order的Value值越小,執(zhí)行的優(yōu)先級就越高。

二,我們可以使用@EventListener輕松標記一個方法作為監(jiān)聽器,但是默認情況下,它是同步執(zhí)行的,所以如果發(fā)布事件的方法處于事務(wù)中,那么事務(wù)會在監(jiān)聽器方法執(zhí)行完畢之后才提交。

有些情況下,我們希望事件發(fā)布之后就由監(jiān)聽器去處理,而不要影響原有的事務(wù),也就是說希望事務(wù)及時提交。

這時我們可以使用@TransactionalEventListener來定義一個監(jiān)聽器。

@Component
public class MessageListener {
    //上層事務(wù)執(zhí)行完畢之后再執(zhí)行
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
    public void listen(MessageEvent messageEvent) {
        System.out.println(Thread.currentThread().getName());
        System.out.println("收到消息:" + messageEvent.getContent());
    }
}

三,默認情況下,@EventListener定義的方法是同步執(zhí)行的,如果我們想通過異步的方式執(zhí)行一個監(jiān)聽器的方法,可以在方法上加上@Async注解(記得在啟動類上加上@EnableAsync開啟異步執(zhí)行配置)。

需要注意的是,使用@Async時,必須為其配置線程池,否則用的還是默認的線程。

如@Async(value = "taskExecutor"),此時Listener就會被分配到taskExecutor的線程池中執(zhí)行。

使用@Async異步執(zhí)行的同時,還會帶來另外兩個問題,需要大家注意:

1,如果Listener執(zhí)行過程中拋出了異常,由于是異步執(zhí)行,異常并不會被事件發(fā)布方捕獲。

2,異步執(zhí)行時,方法的返回值不能用來發(fā)布后續(xù)事件,如果需要處理結(jié)果去發(fā)布另一個事件,需要我們手動去發(fā)布。

4,常見錯誤一:錯誤的監(jiān)聽一個并不會拋出的事件

有時我們希望監(jiān)聽Spring的啟動事件,做一些初始化操作。于是有的同學(xué)可能定義了這樣一個Listener:

@Component
public class MessageListener {
    @EventListener
    public void listen2(ContextStartedEvent event) {
        System.out.println("Spring啟動了," + event.toString());
    }
}

不過,雖然名字看起來似乎是一個上下文啟動時的事件,但是Spring啟動時并不會發(fā)布這個事件,我們啟動項目看下控制臺是否會打印日志:

可以看到,Spring項目啟動后,并沒有打印任何日志。

其實Spring項目啟動后發(fā)布的真正Event是ContextRefreshedEvent,我們修改下代碼再看一下結(jié)果:

這時,控制臺打印出了我們想要的日志。

在創(chuàng)建監(jiān)聽事件時,一定要確保監(jiān)聽的Event是正確的,否則就會監(jiān)聽不到對應(yīng)的事件。

5,常見錯誤二:由于異常導(dǎo)致的事件傳播丟失

即使我們保證事件會被監(jiān)聽器真正的捕獲,但是某些情況下,事件會因為異常導(dǎo)致傳播丟失。

如上圖所示,我們定義了兩個Listener,原本期望按照order定義的順序,將消息傳播依次傳播。然而因為一些原因,Listener1中的方法拋出了異常,導(dǎo)致Listener2無法接收到消息了。

這是因為:默認情況下處理器的執(zhí)行是順序執(zhí)行的,在執(zhí)行過程中,如果一個監(jiān)聽器執(zhí)行拋出了異常,則后續(xù)監(jiān)聽器就得不到被執(zhí)行的機會了。

我們可以通過SimpleApplicationEventMulticaster中的multicastEvent方法看一下事件是如何傳播的,

通過上圖可以看出,如果在沒有定義線程池的情況下,在invokeListener方法中會調(diào)用doInvokeListener方法去執(zhí)行真正的邏輯,在doInvokeListener方法中,如果拋出了異常,會導(dǎo)致后的Listener失效。

針對異常這種情況又該如何處理我們的代碼呢?

有三種方法:

1,使用try catch捕獲異常,只要Listener方法不拋出異常,自然每個Listener都可以收到廣播的消息。

2,使用@Async異步執(zhí)行,通過上面的源碼可以看到,如果定義的線程池,那么每一個Listener都會在一個線程中執(zhí)行,每個線程之后是相互獨立的,自然不會影響別人。

3,通過ErrorHandler處理掉異常,保證后面的Listener不受影響。

總結(jié)

本文主要講解了SpringEvent基本的使用方法,和平常開發(fā)中可能會遇到的一些問題??偟膩碚f,Spring為了讓大家用的更輕松,考慮了各種可能發(fā)生的情況,但是如果大家不了解背后的實現(xiàn)原理,就可能發(fā)生一些本不該出現(xiàn)的bug。

以上就是SpringEvent優(yōu)雅解耦時連續(xù)兩個bug的解決方案的詳細內(nèi)容,更多關(guān)于SpringEvent解耦bug解決的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go依賴注入管理工具wire的使用方法

    go依賴注入管理工具wire的使用方法

    本文主要介紹了如何使用go wire管理依賴,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-09-09
  • Go語言中defer使用的陷阱小結(jié)

    Go語言中defer使用的陷阱小結(jié)

    本文主要介紹了Go語言中defer使用的陷阱小結(jié),分別是defer語句不可以在return語句之后,defer語句執(zhí)行的匿名函數(shù),匿名函數(shù)的參數(shù)會被預(yù)先處理,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • 為什么Go語言把類型聲明放在后面?

    為什么Go語言把類型聲明放在后面?

    今天小編就為大家分享一篇關(guān)于為什么Go語言把類型聲明放在后面?,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • 為什么GO不支持循環(huán)引用

    為什么GO不支持循環(huán)引用

    這篇文章主要介紹的是為什么GO不支持循環(huán)引用,學(xué)習(xí) Go 語言的開發(fā)者越來越多了,很多小伙伴在使用時,就會遇到種種不理解的問題,其中一點就是包的循環(huán)引用的報錯,下main文章我們一起來看看學(xué)習(xí)原因
    2021-10-10
  • Golang分布式應(yīng)用定時任務(wù)示例詳解

    Golang分布式應(yīng)用定時任務(wù)示例詳解

    這篇文章主要為大家介紹了Golang分布式應(yīng)用定時任務(wù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 這些關(guān)于Go中interface{}的注意事項你都了解嗎

    這些關(guān)于Go中interface{}的注意事項你都了解嗎

    這篇文章主要為大家詳細介紹了學(xué)習(xí)Go語言時需要了解的interface{}注意事項,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-03-03
  • golang開發(fā)go包依賴管理godep使用教程

    golang開發(fā)go包依賴管理godep使用教程

    這篇文章主要為大家介紹了golang開發(fā)go包依賴管理godep使用教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-11-11
  • Go語言函數(shù)的延遲調(diào)用(Deferred Code)詳解

    Go語言函數(shù)的延遲調(diào)用(Deferred Code)詳解

    本文將介紹Go語言函數(shù)和方法中的延遲調(diào)用,正如名稱一樣,這部分定義不會立即執(zhí)行,一般會在函數(shù)返回前再被調(diào)用,我們通過一些示例來了解一下延遲調(diào)用的使用場景
    2022-07-07
  • 詳解Golang開啟http服務(wù)的三種方式

    詳解Golang開啟http服務(wù)的三種方式

    這篇文章主要介紹了詳解Golang開啟http服務(wù)的三種方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 自己動手用Golang實現(xiàn)約瑟夫環(huán)算法的示例

    自己動手用Golang實現(xiàn)約瑟夫環(huán)算法的示例

    這篇文章主要介紹了自己動手用Golang實現(xiàn)約瑟夫環(huán)算法的示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12

最新評論