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

Springboot異步事件配置和使用示例詳解

 更新時(shí)間:2024年10月24日 08:59:34   作者:冰雪女媧  
Spring框架提供了一套事件處理機(jī)制,允許應(yīng)用在各個(gè)組件之間傳遞狀態(tài)信息,自定義事件通常繼承自ApplicationEvent類,Springboot通過自動(dòng)配置簡化了異步處理的配置,實(shí)現(xiàn)開箱即用,Spring事件模型核心是觀察者模式,適用于解耦和提高響應(yīng)速度

Spring中提供了完整的事件處理機(jī)制,本身底層內(nèi)置實(shí)現(xiàn)了一些事件和監(jiān)聽,同時(shí)支持開發(fā)者擴(kuò)展自己的事件和監(jiān)聽實(shí)現(xiàn)。

一般這種基于事件的實(shí)現(xiàn)在項(xiàng)目實(shí)際開發(fā)中我們主要用來解耦,和做異步處理(默認(rèn)是同步),提供應(yīng)用的響應(yīng)速度。

核心架構(gòu)

先簡要看一下,在Spring中要實(shí)現(xiàn)自定義事件監(jiān)聽需要涉及哪些接口類,這里忽略異步的引用、注解的實(shí)現(xiàn),后面會(huì)說到。

image

基本實(shí)現(xiàn)步驟

  • 自定義事件:一般繼承自ApplicationEvent即可,注意里面要去定義和實(shí)現(xiàn)自己的事件方法,也就是具體這個(gè)事件要做什么事,一般就在事件類、或者基于事件類去實(shí)現(xiàn)即可。
  • 事件發(fā)布:業(yè)務(wù)代碼中注入ApplicationEventPublisher類,然后再具體業(yè)務(wù)方法中調(diào)用publishEvent方法,傳入上面自定義的事件,以及自定義的必要參數(shù)等信息
  • 實(shí)現(xiàn)事件監(jiān)聽:有了事件、也發(fā)布了,那必須有對(duì)應(yīng)的監(jiān)聽來調(diào)用具體的事件,一般實(shí)現(xiàn)ApplicationListener泛型傳入自己的事件類型即可

注意事項(xiàng)

  • 異常和事物:默認(rèn)情況下事件的發(fā)布、監(jiān)聽處理都是和當(dāng)前業(yè)務(wù)線程綁定到一起的,也就是在同一個(gè)線程中操作事件任務(wù)。因此無論是事件發(fā)布時(shí)導(dǎo)致異常,或者是具體事件任務(wù)實(shí)現(xiàn)的方法異常,都會(huì)導(dǎo)致當(dāng)前業(yè)務(wù)異常;相應(yīng)的如果當(dāng)前業(yè)務(wù)有事物,那么異常了也會(huì)回滾。
  • 事件類型:首先一定要自定義自己的事件,其次在監(jiān)聽的時(shí)候也是監(jiān)聽自己的事件,而不是監(jiān)聽基類或者接口然后去判斷,這樣反而失去了基于事件監(jiān)聽編程靈活性,同時(shí)也違法開閉原則,并不利于后期擴(kuò)展。具體事件中可以定義其他一些額外的參數(shù),這樣方便在具體方法中傳參使用
  • 事件順序:一次可以發(fā)布多個(gè)事件,無論是同一個(gè)還是不同的,執(zhí)行順序默認(rèn)也是按照發(fā)布順序。

場景應(yīng)用

這里以訂單完成和推送給平臺(tái)訂單相關(guān)數(shù)據(jù)為業(yè)務(wù)模型來舉例說明。Spring4.2之后提供了注解來實(shí)現(xiàn)事件監(jiān)聽,非常的方便,這里我們使用注解的方式實(shí)現(xiàn)監(jiān)聽即可。

  • 縮略的業(yè)務(wù)類:包含事件的發(fā)布
@Resource
private ApplicationEventPublisher publisher;
public void completeTrade(TradeOrder trade){
  tradeMapper.modifyStatus(trade);
  publisher.publishEvent(new TradeStatusEvent(this,new TradeStatusEvent.Params(trade,"完成訂單")));
}
  • 具體事件的定義:繼承自ApplicationEvent
public class TradeStatusEvent extends ApplicationEvent {
    private static final Logger logger = LoggerFactory.getLogger(TradeStatusEvent.class);
    private Params params;
    public Params getParams(){
      return this.params;
    }
    public TradeStatusEvent(Object source,Params param) {
        super(source);
        this.param = param;
    }
    public void send(){
      try{
        HttpUtils.send("xx.oo", PlatformBean.Builder().note(this.params.note)..build());
      } catch(Exception e){
        logger.error("TradeStatusEvent處理異常:",e);
      } 
    }
    public static class Params {
        private TradeOrder trade;
        private String note;
        //get、set 定義其他參數(shù)等
    }
}
  • 監(jiān)聽實(shí)現(xiàn):使用注解,注意這里我使用了 事務(wù)監(jiān)聽注解 ,按照具體業(yè)務(wù)場景可以選擇具體的注解,比如最常用的@EventListener。因?yàn)槲疫@里的訴求是當(dāng)前事物提交完成之后再去推送消息,而且實(shí)際情況是啟用了異步監(jiān)聽來實(shí)現(xiàn),同時(shí)有的人在監(jiān)聽的方法中可能還執(zhí)行了回查,也就是去查詢業(yè)務(wù)中提交的數(shù)據(jù),那如果這里不標(biāo)記為事物提交之后執(zhí)行,在異步情況下無法獲取到數(shù)據(jù)
@Component
public class TradeStatusEventListener {
    @TransactionalEventListener(phase= TransactionPhase.AFTER_COMMIT, fallbackExecution=true)
    void handlerAfterComplete(TradeStatusEvent event) {
        event.send();
    }
}

異步實(shí)現(xiàn)

所謂異步實(shí)現(xiàn),一般是指異步監(jiān)聽,將主體業(yè)務(wù)邏輯和消息監(jiān)聽任務(wù)放到不同的線程去執(zhí)行,提高業(yè)務(wù)的響應(yīng)速度。

Springboot中我們有多個(gè)辦法來實(shí)現(xiàn)異步監(jiān)聽執(zhí)行,最簡單、最直接的就和異步方法實(shí)現(xiàn)一模一樣,只需在監(jiān)聽方法上加上@Async注解(前提是啟用了異步執(zhí)行)

  • 第一種辦法:Configuration配置類中加上注解@EnableAsync,啟用Spring的異步方法執(zhí)行能力。然后在監(jiān)聽方法上加上@Async注解,標(biāo)明此方法是異步執(zhí)行。Over就這樣就行了【我們沒有配置異步線程對(duì)不對(duì)?那是會(huì)直接new Thread()來執(zhí)行異步任務(wù)嗎,當(dāng)然不是,而是Spring默認(rèn)提供并初始化了一個(gè)專門用來執(zhí)行異步任務(wù)的線程池ThreadPoolTaskExecutor,會(huì)接管所有的異步任務(wù)在同一個(gè)線程池中執(zhí)行。也支持定制化處理,后續(xù)我們會(huì)說到】
@Configuration
@EnableAsync
public class AppConfig{}
//````
@Component
public class TradeStatusEventListener {
    @Async
    @TransactionalEventListener(phase= TransactionPhase.AFTER_COMMIT, fallbackExecution=true)
    void handlerAfterComplete(TradeStatusEvent event) {
        event.send();
    }
}
  • 第二種辦法:如果說不想全局開啟異步,只是想給事件監(jiān)聽的代碼實(shí)現(xiàn)異步任務(wù)呢?那最簡單就是直接在監(jiān)聽哪里new Thread().start(),不受控、不優(yōu)雅,但是業(yè)務(wù)場景簡單,訪問量小的情況下也不是不可以。那要規(guī)范一點(diǎn)呢,就是自己創(chuàng)建一個(gè)線程池,比如ExecutorService executorService = Executors.newCachedThreadPool();然后在event.send哪里使用executorService.execute(..)執(zhí)行即可。
  • 第三種辦法:優(yōu)雅點(diǎn)實(shí)現(xiàn),創(chuàng)建SimpleApplicationEventMulticaster的Bean,然后創(chuàng)建一個(gè)線程池給塞進(jìn)去,注意需要把自定義實(shí)現(xiàn)注入到Spring容器中。其他代碼不用做任何修改,就像同步邏輯一樣,在事件發(fā)布的時(shí)候廣播會(huì)使用multicastEvent調(diào)用taskExecutor獲取一個(gè)線程去執(zhí)行監(jiān)聽任務(wù)
@Configuration
public class AppConfig{
  @Bean
  public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster(){
        SimpleApplicationEventMulticaster mu = new SimpleApplicationEventMulticaster();
        //這里我使用spring提供的任務(wù)構(gòu)造器創(chuàng)建了一個(gè)立即執(zhí)行的有界隊(duì)列任務(wù)線程池
        Executor taskExecutor = new TaskExecutorBuilder().corePoolSize(8).maxPoolSize(200).queueCapacity(20).threadNamePrefix("trade-send-").build();
        mu.setTaskExecutor(taskExecutor);
        //設(shè)置異常處理
        mu.setErrorHandler((t)->{
            //logger.error("==========調(diào)用平臺(tái)發(fā)送消息方法失敗,",t);
        });
    return mu;
  }
}

框架原理

  • 為什么異步監(jiān)聽只需要@EnableAsync、以及在方法上加上@Async就可以了呢?

當(dāng)我們使用Springboot,引入starter時(shí)會(huì)自動(dòng)引入spring-boot-autoconfigure,此包里面實(shí)現(xiàn)了很多自動(dòng)配置的功能(約定大于配置)名字都是xxxAutoConfiguration,比如我們這里要說的就是TaskExecutionAutoConfiguration,容器啟動(dòng)的時(shí)候就會(huì)加載和創(chuàng)建默認(rèn)的任務(wù)線程池,可以通過spring.task.execution開頭屬性來配置。需要注意的是,無論是否加入@EnableAsync注解TaskExecutionAutoConfiguration都會(huì)初始化一個(gè)默認(rèn)的線程池,因?yàn)檫@個(gè)是全局的。

image

@EnableAsync的作用是在容器啟動(dòng)的時(shí)候,告訴Spring我可要支持異步處理任務(wù)了,你看著辦。Spring所好的朋友,我給你準(zhǔn)備了一個(gè)專門搞事的攔截器。

image

  • 當(dāng)我們加入了注解,Spring會(huì)將按照配置將準(zhǔn)備工作全部做完,從而做到開箱即用,直接一步到位。

總結(jié)

  • Spring事件模型的四個(gè)核心:事件源也就是業(yè)務(wù)方、事件、廣播器、監(jiān)聽器
  • 事件機(jī)制支持同步、異步,按需調(diào)整和使用。使用異步監(jiān)聽時(shí),推薦使用線程池管理線程,高效、穩(wěn)定而且易于維護(hù)。
  • 使用Springboot時(shí)通過注解的方式監(jiān)聽、啟用異步盡享絲滑。實(shí)際原理核心就是觀察者模式。

到此這篇關(guān)于Springboot異步事件配置和使用的文章就介紹到這了,更多相關(guān)Springboot異步事件配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Skywalking改成適配阿里云等帶Http?Basic的Elasticsearch服務(wù)

    Skywalking改成適配阿里云等帶Http?Basic的Elasticsearch服務(wù)

    這篇文章主要介紹了改造Skywalking支持阿里云等帶Http?Basic的Elasticsearch服務(wù)
    2022-02-02
  • 詳解Swagger接口文檔和常用注解的使用

    詳解Swagger接口文檔和常用注解的使用

    Swagger是一款遵循?Restful?風(fēng)格的接口文檔開發(fā)神器,支持基于?API?自動(dòng)生成接口文檔。本文將為大家講講Swagger接口文檔和常用注解的使用方法,需要的可以參考一下
    2022-08-08
  • 細(xì)品Java8中hashCode方法的使用

    細(xì)品Java8中hashCode方法的使用

    這篇文章主要介紹了細(xì)品Java8中hashCode方法的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 淺談JVM內(nèi)存溢出原因和解決思路

    淺談JVM內(nèi)存溢出原因和解決思路

    本文主要介紹了淺談JVM內(nèi)存溢出原因和解決思路,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 關(guān)于Java?CPU或內(nèi)存使用率過高問題定位

    關(guān)于Java?CPU或內(nèi)存使用率過高問題定位

    Spring?cloud微服務(wù)廣泛應(yīng)用后,服務(wù)的監(jiān)控和運(yùn)維壓力也與日俱增,經(jīng)常有服務(wù)出現(xiàn)CPU或者內(nèi)存使用率過高的告警,那么遇到這樣的問題我們該如何排查呢?我們可以借助哪些工具來定位問題呢?本文將介紹一下遇到此類問題的解決思路和方法
    2024-10-10
  • Java開發(fā)中常用的 Websocket 技術(shù)參考

    Java開發(fā)中常用的 Websocket 技術(shù)參考

    WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù),當(dāng)然也支持客戶端發(fā)送數(shù)據(jù)到服務(wù)端。
    2020-09-09
  • 使用PageHelper插件實(shí)現(xiàn)Service層分頁

    使用PageHelper插件實(shí)現(xiàn)Service層分頁

    這篇文章主要為大家詳細(xì)介紹了使用PageHelper插件實(shí)現(xiàn)Service層分頁,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 詳解JVM如何判斷一個(gè)對(duì)象是否可以被回收

    詳解JVM如何判斷一個(gè)對(duì)象是否可以被回收

    在c++中,當(dāng)我們使用完某個(gè)對(duì)象的時(shí)候,需要顯示的將對(duì)象回收,在java中,jvm會(huì)幫助我們進(jìn)行垃圾回收,無需程序員自己寫代碼進(jìn)行回收,下面我們就來看看JVM是如何判斷一個(gè)對(duì)象是否可以被回收的吧
    2023-11-11
  • java秒殺系統(tǒng)常見問題庫存超賣解決實(shí)例分析

    java秒殺系統(tǒng)常見問題庫存超賣解決實(shí)例分析

    這篇文章主要為大家介紹了java秒殺系統(tǒng)常見問題庫存超賣解決實(shí)例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • CountDownLatch源碼解析之countDown()

    CountDownLatch源碼解析之countDown()

    這篇文章主要為大家詳細(xì)解析了CountDownLatch源碼之countDown方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04

最新評(píng)論