SpringBoot使用Async註解失效原因分析及解決(spring異步回調)

Async註解失效原因分析及解決(spring異步回調)

Spring中@Async

在Java應用中,絕大多數情況下都是通過同步的方式來實現交互處理的;但是在處理與第三方系統交互的時候,容易造成響應遲緩的情況,之前大部分都是使用多線程來完成此類任務,其實,在spring 3.x之後,就已經內置瞭@Async來完美解決這個問題

有時候在使用的過程中@Async註解會失效

(原因和@Transactional註解有時候會失效的原因一樣)。

下面定義一個Service:

兩個異步執行的方法test03()和test02()用來模擬項目中可能出現的耗時操作,然後test()方法調用這兩個耗時的方法:

SpringBoot使用Async註解失效分析、解決(spring異步回調)

定義Controller:

SpringBoot使用Async註解失效分析、解決(spring異步回調)

執行方法,返回結果:

SpringBoot使用Async註解失效分析、解決(spring異步回調)

方法執行結果明顯與我們的預期不符,方法的輸出順序表示瞭test02()和test03()兩個異步方法居然同步執行瞭,也就是說@Aysnc註解失效瞭!

失效的原因是因為我們是在test()方法中直接調用的test02()和test03()方法,相當於是this.test02()和this.test03()調用的,也就是說真正調用test02()和test03()方法的是TestService對象本身調用的,而@Async和@Transactional註解本質使用的是動態代理,真正應該是TestService的代理對象調用test02()和test03()方法。其實Spring容器在初始化的時候Spring容器會將含有AOP註解的類對象“替換”為代理對象(簡單這麼理解),那麼註解失效的原因就很明顯瞭,就是因為調用方法的是對象本身而不是代理對象,因為沒有經過Spring容器,那麼解決方法也會沿著這個思路來解決。

網上有不少博客說解決方法就是將要異步執行的方法單獨抽取成一個類,這樣的確可以解決異步註解失效的問題,原理就是當你把執行異步的方法單獨抽取成一個類的時候,這個類肯定是被Spring管理的,其他Spring組件需要調用的時候肯定會註入進去,這時候實際上註入進去的就是代理類瞭,其實還有其他的解決方法,並不一定非要單獨抽取成一個類。

解決方式一

在TestService中通過上下文獲取自己的代理對象調用異步方法

其實我們的註入對象都是從Spring容器中給當前Spring組件進行成員變量的賦值,由於TestService使用瞭AOP註解,那麼實際上TestService在Spring容器中實際存在的是它的代理對象。

SpringUtil工具類可以參考:http://mp.toutiao.com/preview_article/?pgc_id=6638488982025929223

SpringBoot使用Async註解失效分析、解決(spring異步回調)

執行結果,異步方法異步執行瞭:

SpringBoot使用Async註解失效分析、解決(spring異步回調)

解決方式二

開啟cglib代理,手動獲取Spring代理類

在啟動類上加上:

SpringBoot使用Async註解失效分析、解決(spring異步回調)

使用AopContext.currentProxy()獲取當前代理類:

這裡為瞭證明Spring容器中的對象就是當前代理類對象特地輸出瞭一句話:

SpringBoot使用Async註解失效分析、解決(spring異步回調)

運行結果:

SpringBoot使用Async註解失效分析、解決(spring異步回調)

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、當前類中其他函數調用有 @Async 註解的函數

2、當前類中有多態,方法名相同

3、啟動類未加@EnableAsync

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: