Async注解失效原因分析及解決(spring異步回調)
Spring中@Async
在Java應用中,絕大多數情況下都是通過同步的方式來實現交互處理的;但是在處理與第三方系統交互的時候,容易造成響應遲緩的情況,之前大部分都是使用多線程來完成此類任務,其實,在spring 3.x之后,就已經內置了@Async來完美解決這個問題
有時候在使用的過程中@Async注解會失效
(原因和@Transactional注解有時候會失效的原因一樣)。
下面定義一個Service:
兩個異步執行的方法test03()和test02()用來模擬項目中可能出現的耗時操作,然后test()方法調用這兩個耗時的方法:
定義Controller:
執行方法,返回結果:
方法執行結果明顯與我們的預期不符,方法的輸出順序表示了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
執行結果,異步方法異步執行了:
解決方式二
開啟cglib代理,手動獲取Spring代理類
在啟動類上加上:
使用AopContext.currentProxy()獲取當前代理類:
這里為了證明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
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/u011277123/article/details/85250012/