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

Springboot配置@Async無效的解決方案

 更新時(shí)間:2023年09月27日 09:57:50   作者:唐宋xy  
這篇文章主要介紹了Springboot配置@Async無效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Springboot配置@Async無效

Springboot中為了同時(shí)執(zhí)行多個(gè)任務(wù),或者同時(shí)查詢,加快查詢則使用多線程查詢,在springboot中,可以直接使用 @Async注解來實(shí)現(xiàn)異步任務(wù),可以參考Springboot使用@Async實(shí)現(xiàn)異步任務(wù)簡(jiǎn)單快捷使用,但是異步任務(wù)在某些情況下居然無效。

配置正確,代碼不報(bào)錯(cuò),但是無法使用多線程異步任務(wù),可能是下面的原因?qū)е拢?/strong>

1.沒有在springboot啟動(dòng)類當(dāng)中添加注解 @EnableAsync注解。

2.異步方法使用注解@Async的返回值只能為void或者Future。

3.沒有走Spring的代理類。

因?yàn)锧Transactional和@Async注解的實(shí)現(xiàn)都是基于Spring的AOP,而AOP的實(shí)現(xiàn)是基于動(dòng)態(tài)代理實(shí)現(xiàn)的。

那么注解失效的原因就很明顯了,有可能因?yàn)檎{(diào)用方法的是對(duì)象本身而不是代理對(duì)象,沒有經(jīng)過Spring容器,無法使用代理對(duì)象調(diào)用。

4.注解的方法必須是 public 方法。編譯時(shí)非public方法會(huì)報(bào)錯(cuò)

5.如果需要從 類的內(nèi)部 調(diào)用,需要先獲取其代理類

先注入ApplicationContext

@Autowired
private ApplicationContext applicationContext;

然后在方法中通過ApplicationContext對(duì)象獲取當(dāng)前類對(duì)象

applicationContext.getBean(Class);

6.調(diào)用的是靜態(tài)(static )方法,也會(huì)導(dǎo)致注解失效,因?yàn)樽⒔馐腔诖韺?duì)象調(diào)用,而static方法是屬于類的,無法通過spring的代理對(duì)象直接調(diào)用

Springboot @Async失效的坑

異步應(yīng)用場(chǎng)景

為了提高接口的響應(yīng)性能,當(dāng)業(yè)務(wù)非常復(fù)雜的情況下,可以將一部分跟業(yè)務(wù)關(guān)聯(lián)性不是特別強(qiáng)的邏輯進(jìn)行異步處理。如日志記錄、短信發(fā)送、增加積分等。

通常而言會(huì)將此類業(yè)務(wù)邏輯通過異步的方式進(jìn)行處理,從而加快接口的響應(yīng)速度,常用的解決方案有:

  • 使用JDK 自定義線程池 讓代碼異步執(zhí)行
  • 在springboot 中 使用@Async注解進(jìn)行異步處理
  • 使用中間件如mq 消息通知讓下游異步消費(fèi) 如RocketMQ、KAFKA

使用第一種方式,需要精通線程池運(yùn)行原理,結(jié)合實(shí)際的業(yè)務(wù)場(chǎng)景對(duì)隊(duì)列大小進(jìn)行合理的設(shè)置。隊(duì)列設(shè)置過大過小都會(huì)存在內(nèi)存溢出的風(fēng)險(xiǎn)。

第三種方式是最合理的方式,它能夠通過MQ進(jìn)行削峰填谷,通過合理的參數(shù)配置,保證數(shù)據(jù)不會(huì)丟失。但是架構(gòu)改動(dòng)過大,對(duì)小型的單體應(yīng)用來講,工作量過大,成本過高。

在springboot 大行其道的情況下,考慮開發(fā)成本,以及項(xiàng)目時(shí)間關(guān)系選用第二種方式來解決代碼異步執(zhí)行的問題。

真實(shí)業(yè)務(wù)場(chǎng)景

線上問題

一個(gè)工單的分頁列表,前端控制了每個(gè)列表最大的顯示條數(shù)為100條。在業(yè)務(wù)流程中存在工單轉(zhuǎn)移的操作,轉(zhuǎn)移一筆工單至少包含以下幾個(gè)重要的步驟:

  • 新增工單處理日志,如什么時(shí)間點(diǎn)將工單轉(zhuǎn)移給某人
  • 修改工單當(dāng)前處理人
  • 發(fā)送企業(yè)微信給B端的跟進(jìn)人(轉(zhuǎn)移人)
  • 發(fā)送im信息給C端的用戶

由于公司采用微服務(wù)架構(gòu),因此每個(gè)業(yè)務(wù)模塊拆分的很細(xì),在上述步驟中需要從其他系統(tǒng)中通過rpc調(diào)用接口拿到需要的數(shù)據(jù)才能完成整個(gè)業(yè)務(wù)流程數(shù)據(jù)的拼裝,如需要從crm系統(tǒng)拿到組織架構(gòu)信息,獲取轉(zhuǎn)移人的組織架構(gòu)、需要從udb用戶中心獲取轉(zhuǎn)移人的企業(yè)微信昵稱等。

因此在批量轉(zhuǎn)移的時(shí)候,前端會(huì)出現(xiàn)調(diào)用超時(shí)的問題,原因是dubbo接口默認(rèn)的超時(shí)時(shí)間是15秒,由于業(yè)務(wù)復(fù)雜,導(dǎo)致在15秒內(nèi)執(zhí)行不完業(yè)務(wù)邏輯。

解決方案

  • 將sql處理改為批量執(zhí)行,如新增處理日志 (batch insert);修改當(dāng)前工單,使用case when 的方式一次性修改完成(批量update)
  • 將發(fā)送消息改成異步處理 加快前端接口的響應(yīng)速度
  • 讓接口提供方提供批量查詢的接口,避免rpc 循環(huán)調(diào)用在網(wǎng)絡(luò)上的消耗

優(yōu)化完成之后,接口的響應(yīng)速度由15秒多,變成了1秒。但是過程中遇到坑了。特此記錄一下

技術(shù)實(shí)現(xiàn)

優(yōu)化過程

@Async 注解定義為可以放置在方法上和類上,當(dāng)使用在類上表明類所有的方法都能異步執(zhí)行。

在Springboot中是需要在方法上加上該注解就可以完美的實(shí)現(xiàn)異步執(zhí)行。

原始方法偽代碼如下

/**
 * 原始代碼 采用流水式的代碼一步步實(shí)現(xiàn) 業(yè)務(wù)邏輯
 */
public void doBusiness(Object args){
  //1.  新增工單處理日志,如什么時(shí)間點(diǎn)將工單轉(zhuǎn)移給某人
  //2. 修改工單當(dāng)前處理人
  //3. 發(fā)送企業(yè)微信給B端的跟進(jìn)人(轉(zhuǎn)移人)
  //4. 發(fā)送im信息給C端的用戶
}

那么異步問題就很好處理了,只需要將方法抽離形成多個(gè)子方法, 每個(gè)方法執(zhí)行自己的業(yè)務(wù)處理邏輯,然后再方法加上@Async注解不就ok了么,偽代碼如下

public void doBusiness(Object args){
 	//2. 修改工單當(dāng)前處理人
  this.doAsyncBusiness();
}
// 單獨(dú)抽離一個(gè)異步執(zhí)行的方法 加上@Async注解
@Async
private void doAsyncBusiness(Object args){
  //1.  新增工單處理日志,如什么時(shí)間點(diǎn)將工單轉(zhuǎn)移給某人
  //3. 發(fā)送企業(yè)微信給B端的跟進(jìn)人(轉(zhuǎn)移人)
  //4. 發(fā)送im信息給C端的用戶
}

打完收工,重啟應(yīng)用,進(jìn)行測(cè)試,然而并沒有像預(yù)期中的那樣,接口的響應(yīng)速度還是15秒左右。接著排查原因,可以肯定的是@Async是可以提供異步方法執(zhí)行。應(yīng)該是我們使用方式不對(duì)導(dǎo)致。

@Async 限制

熟悉Springboot AOP的同學(xué)可能會(huì)發(fā)現(xiàn)更改后的代碼存在明顯的問題

  • 首先AOP代理機(jī)制要求 被代理的方法必須是 public , private 方法不能被代理
  • 其次AOP代理機(jī)制會(huì)生成一個(gè)代理類 執(zhí)行代理方法 注意 this.doAsyncBusiness() 調(diào)用的是本對(duì)象的方法 ;
  • 在啟動(dòng)類上加上@EnableAsync注解

綜上所述,原因我們已經(jīng)通過AOP代理的原理找到了。下面摘自官方文檔的一段話:

  • it must be applied to public methods only
  • self-invocation – calling the async method from within the same class – won’t work

The reasons are simple – 「the method needs to be public」 so that it can be proxied. And 「self-invocation doesn’t work」 because it bypasses the proxy and calls the underlying method directly.

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 利用Intellij Idea連接遠(yuǎn)程服務(wù)器實(shí)現(xiàn)遠(yuǎn)程上傳部署功能

    利用Intellij Idea連接遠(yuǎn)程服務(wù)器實(shí)現(xiàn)遠(yuǎn)程上傳部署功能

    大家在使用Intellij Idea開發(fā)程序的時(shí)候,是不是需要部署到遠(yuǎn)程SSH服務(wù)器運(yùn)行呢,當(dāng)然也可以直接在idea軟件內(nèi)容實(shí)現(xiàn)配置部署操作,接下來通過本文給大家分享利用Intellij Idea連接遠(yuǎn)程服務(wù)器實(shí)現(xiàn)遠(yuǎn)程上傳部署功能,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • 詳解Spring 注解之@Import 注入的各種花活

    詳解Spring 注解之@Import 注入的各種花活

    這篇文章主要介紹了詳解Spring 注解之@Import 注入的各種花活,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Java變量與運(yùn)算符用法詳解

    Java變量與運(yùn)算符用法詳解

    這篇文章介紹了Java中的關(guān)鍵字、標(biāo)識(shí)符、變量、基本數(shù)據(jù)類型、變量作用域、基本數(shù)據(jù)類型間的運(yùn)算、字符串、基本數(shù)據(jù)類型與字符串的運(yùn)算、計(jì)算機(jī)底層數(shù)據(jù)存儲(chǔ)、運(yùn)算符的使用、賦值運(yùn)算符、比較運(yùn)算符、邏輯運(yùn)算符、位運(yùn)算符和條件運(yùn)算符用法,感興趣的朋友跟隨小編看看吧
    2026-01-01
  • Java之Thread的join方法實(shí)例

    Java之Thread的join方法實(shí)例

    這篇文章主要介紹了Java之Thread的join方法,實(shí)例形式講述了join方法的應(yīng)用,需要的朋友可以參考下
    2014-10-10
  • RepeatSubmit若依框架如何防止表單重復(fù)提交注解

    RepeatSubmit若依框架如何防止表單重復(fù)提交注解

    若依框架中的@RepeatSubmit注解用于防止表單重復(fù)提交,通過在控制器方法上添加該注解,并在前端頁面和JavaScript代碼中實(shí)現(xiàn)雙重校驗(yàn),可以確保同一用戶在短時(shí)間內(nèi)不會(huì)重復(fù)提交相同的表單
    2024-11-11
  • 用java生成html文件實(shí)現(xiàn)原理及代碼

    用java生成html文件實(shí)現(xiàn)原理及代碼

    用printStream來向html文件里輸出數(shù)據(jù),先創(chuàng)建一個(gè)StringBuilder對(duì)象,通過append方法來為其添加html語句,具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下,希望對(duì)大家有所幫助
    2013-08-08
  • springboot springmvc拋出全局異常的解決方法

    springboot springmvc拋出全局異常的解決方法

    這篇文章主要為大家詳細(xì)介紹了springboot springmvc拋出全局異常的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Java的Hibernate框架中的雙向主鍵關(guān)聯(lián)與雙向外鍵關(guān)聯(lián)

    Java的Hibernate框架中的雙向主鍵關(guān)聯(lián)與雙向外鍵關(guān)聯(lián)

    Hibernate想要實(shí)現(xiàn)雙向的關(guān)聯(lián)就必須在映射文件的兩端同時(shí)配置<one-to-one>,另外還要在主映射的一端采用foreign外鍵關(guān)聯(lián)屬性,下面我們就一起來看一下Java的Hibernate框架中的雙向主鍵關(guān)聯(lián)與雙向外鍵關(guān)聯(lián)方法:
    2016-06-06
  • 淺談Java響應(yīng)式系統(tǒng)

    淺談Java響應(yīng)式系統(tǒng)

    第一次聽到reactive這個(gè)詞還是在幾年前,偶然了解到了Rxjava這個(gè)項(xiàng)目,仿佛為我打開了一扇新的大門,Rxjava是ReactiveX的java實(shí)現(xiàn),ReactiveX家族除了Rxjava還有RxJS, Rx.NET,RxScala等等。
    2021-06-06
  • Java設(shè)計(jì)模式之責(zé)任鏈模式

    Java設(shè)計(jì)模式之責(zé)任鏈模式

    今天小編就為大家分享一篇關(guān)于Java設(shè)計(jì)模式之責(zé)任鏈模式,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評(píng)論

兰州市| 阿尔山市| 田阳县| 手机| 五常市| 吉安县| 上栗县| 临海市| 公主岭市| 赤峰市| 华亭县| 正安县| 鄱阳县| 昆山市| 香港 | 长垣县| 巩义市| 河曲县| 疏附县| 远安县| 探索| 东莞市| 曲沃县| 广汉市| 太仓市| 六枝特区| 繁昌县| 富平县| 沈阳市| 凭祥市| 廊坊市| 利辛县| 雅江县| 湾仔区| 辉南县| 湘阴县| 乡城县| 巴楚县| 乌兰浩特市| 邵阳县| 营山县|