在循環依賴中有一種循環依賴,就是自注入:本身依賴本身。java
在 Spring 自調用事務失效,你是怎麼解決的? 有小夥伴提出能夠本身注入本身來解決事務失效。緩存
具體使用方式以下:app
@Slf4j @Service public class OrderBizServiceImpl implements OrderBizService { // 注入本身 @Autowired private OrderBizService orderBizService; @Override public void callBack() throws Exception { // 一系列的邏輯 // 須要事務操做更新訂單和用戶金額 orderBizService.updateOrderStatusAndUserBalance(); } @Override @Transactional(rollbackFor = Exception.class) public void updateOrderStatusAndUserBalance() throws Exception { // 內部是事務邏輯 } }
是否是發現很神奇的事情,事務生效了。異步
其實這裏注入本身,實際上是注入的一個代理對象,調事務,也是調的代理對象的事務,因此事務生效。ide
Spring 事務失效緣由:事務只能應用到 public 方法上纔會有效;
事務須要從外部調用,Spring 自調用會失效;
建議事務註解 @Transactional 通常添加在實現類上。post
發現 @Transactional 註解能夠自注入解決事務失效的問題,在某次開發中,天然而然想到 @Async 異步是否是也能夠自注入解決循環依賴的問題。spa
NO, NO, NO……代理
事實告訴咱們是不能夠的!code
從錯誤開始着手:對象
開始往上面反推 exposedObject == bean 是這一塊出了問題。
也就是說異步的時候,再次從二級緩存中獲取的和初始的不相同。
Object earlySingletonReference = getSingleton(beanName, false);
這一次獲取的時候發現不一樣因此報錯。
那就開始 Debug, 按照循環依賴的邏輯,執行到 populateBean
時,屬性賦值,發現有依賴本身,此時會建立本身。
執行 singleton.getObject 方法
而此時執行 getEarlyBeanReference 先判斷 InfrastructureAdvisorAutoProxyCreator
true 調用 wrapIfNecessary 判斷是否生成一個代理對象,這裏並無生成代理對象。
而後開始執行異步的 AsyncAnnotationBeanPostProcessor
判斷爲 false。因此沒有執行異步的生成代理對象邏輯。
那就繼續往下看
進入到 initializeBean 的邏輯,有一部分叫作 applyBeanPostProcessorsAfterInitialization
方面小夥伴搜索,因此貼出來代碼關鍵字。IDEA 使用
⌘ + Shift + F
搜索。
循環執行後置處理器:
發現執行完 AsyncAnnotationBeanPostProcessor 這個 PostProcessor 後,對象被改變了。從而致使二級緩存和當前的 Bean 不一樣。
以上也就是爲何 @Async 自調用不能夠,由於在後面初始化階段被代理修改了對象。
先判斷 InfrastructureAdvisorAutoProxyCreator true 生成一個代理對象。
事務的處理器 PersistenceExceptionTranslationPostProcessor 也沒有執行。
繼續 Debug 關注 applyBeanPostProcessorsAfterInitialization
執行結束,發現 Bean 沒有發生改變。
exposedObject == bean
爲 false ,從而拋出異常。
能夠看出圖中有兩處會執行 BeanPostProcessor :
也有其餘的地方在執行後置處理器,好比 applyBeanPostProcessorsBeforeInitialization ,只不過這裏關注這倆處。
而這兩處都有可能生成代理對象, @Transactional 是在 getEarlyBeanReference 處生成的代理對象,因此後面判斷 Bean 是否被改變時爲 true,而 @Async 是在後面異步生成了代理對象,因此判斷不經過。
至此,分析完畢,錯誤之處,歡迎指正。