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