SpringBoot使用Async注解失效原因分析及解決(spring異步回調(diào))
Async注解失效原因分析及解決(spring異步回調(diào))
Spring中@Async
在Java應(yīng)用中,絕大多數(shù)情況下都是通過同步的方式來實(shí)現(xiàn)交互處理的;但是在處理與第三方系統(tǒng)交互的時(shí)候,容易造成響應(yīng)遲緩的情況,之前大部分都是使用多線程來完成此類任務(wù),其實(shí),在spring 3.x之后,就已經(jīng)內(nèi)置了@Async來完美解決這個(gè)問題
有時(shí)候在使用的過程中@Async注解會失效
(原因和@Transactional注解有時(shí)候會失效的原因一樣)。
下面定義一個(gè)Service:
兩個(gè)異步執(zhí)行的方法test03()和test02()用來模擬項(xiàng)目中可能出現(xiàn)的耗時(shí)操作,然后test()方法調(diào)用這兩個(gè)耗時(shí)的方法:
定義Controller:
執(zhí)行方法,返回結(jié)果:
方法執(zhí)行結(jié)果明顯與我們的預(yù)期不符,方法的輸出順序表示了test02()和test03()兩個(gè)異步方法居然同步執(zhí)行了,也就是說@Aysnc注解失效了!
失效的原因是因?yàn)槲覀兪窃趖est()方法中直接調(diào)用的test02()和test03()方法,相當(dāng)于是this.test02()和this.test03()調(diào)用的,也就是說真正調(diào)用test02()和test03()方法的是TestService對象本身調(diào)用的,而@Async和@Transactional注解本質(zhì)使用的是動態(tài)代理,真正應(yīng)該是TestService的代理對象調(diào)用test02()和test03()方法。其實(shí)Spring容器在初始化的時(shí)候Spring容器會將含有AOP注解的類對象“替換”為代理對象(簡單這么理解),那么注解失效的原因就很明顯了,就是因?yàn)檎{(diào)用方法的是對象本身而不是代理對象,因?yàn)闆]有經(jīng)過Spring容器,那么解決方法也會沿著這個(gè)思路來解決。
網(wǎng)上有不少博客說解決方法就是將要異步執(zhí)行的方法單獨(dú)抽取成一個(gè)類,這樣的確可以解決異步注解失效的問題,原理就是當(dāng)你把執(zhí)行異步的方法單獨(dú)抽取成一個(gè)類的時(shí)候,這個(gè)類肯定是被Spring管理的,其他Spring組件需要調(diào)用的時(shí)候肯定會注入進(jìn)去,這時(shí)候?qū)嶋H上注入進(jìn)去的就是代理類了,其實(shí)還有其他的解決方法,并不一定非要單獨(dú)抽取成一個(gè)類。
解決方式一
在TestService中通過上下文獲取自己的代理對象調(diào)用異步方法
其實(shí)我們的注入對象都是從Spring容器中給當(dāng)前Spring組件進(jìn)行成員變量的賦值,由于TestService使用了AOP注解,那么實(shí)際上TestService在Spring容器中實(shí)際存在的是它的代理對象。
執(zhí)行結(jié)果,異步方法異步執(zhí)行了:
解決方式二
開啟cglib代理,手動獲取Spring代理類
在啟動類上加上:
使用AopContext.currentProxy()獲取當(dāng)前代理類:
這里為了證明Spring容器中的對象就是當(dāng)前代理類對象特地輸出了一句話:
運(yùn)行結(jié)果:
OK,問題完美解決!
application.properties配置如下:
#java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available. # 增加@EnableAspectJAutoProxy spring.aop.auto=true #開啟CGLIB代理 spring.aop.proxy-target-class=true
springboot @Async 失效可能原因
1、當(dāng)前類中其他函數(shù)調(diào)用有 @Async 注解的函數(shù)
2、當(dāng)前類中有多態(tài),方法名相同
3、啟動類未加@EnableAsync
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Xml中使用foreach遍歷對象實(shí)現(xiàn)代碼
這篇文章主要介紹了Xml中使用foreach遍歷對象實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12springboot中使用過濾器,jsoup過濾XSS腳本詳解
這篇文章主要介紹了springboot中使用過濾器,jsoup過濾XSS腳本詳解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12詳解Java后端優(yōu)雅驗(yàn)證參數(shù)合法性
這篇文章主要介紹了詳解Java后端優(yōu)雅驗(yàn)證參數(shù)合法性,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02spring profile 多環(huán)境配置管理詳解
這篇文章主要介紹了 spring profile 多環(huán)境配置管理詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01Mybatis注解開發(fā)單表、多表操作的實(shí)現(xiàn)代碼
這篇文章主要介紹了Mybatis高級:Mybatis注解開發(fā)單表操作,Mybatis注解開發(fā)多表操作,構(gòu)建sql語句,綜合案例學(xué)生管理系統(tǒng)使用接口注解方式優(yōu)化,需要的朋友可以參考下2021-02-02Spring?boot?自定義?Starter及自動配置的方法
Starter?組件是?Spring?boot?的一個(gè)核心特性,Starter組件的出現(xiàn)極大的簡化了項(xiàng)目開發(fā),這篇文章主要介紹了Spring?boot?自定義?Starter?及?自動配置,需要的朋友可以參考下2022-12-12如何用Intellij idea2020打包jar的方法步驟
這篇文章主要介紹了如何用Intellij idea 2020打包jar的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04