前言
在循環依賴中有一種循環依賴,就是自注入:自己依賴自己。

事務的自注入
在 Spring 自調用事務失效,你是怎么解決的? 有小伙伴提出可以自己注入自己來解決事務失效。
具體使用方式如下:
@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 {
// 內部是事務邏輯
}
}
是不是發現很神奇的事情,事務生效了。
其實這里注入自己,其實是注入的一個代理對象,調事務,也是調的代理對象的事務,所以事務生效。
Spring 事務失效原因:
事務只能應用到 public 方法上才會有效;
事務需要從外部調用,Spring 自調用會失效;
建議事務注解 @Transactional 一般添加在實現類上。
異步的自注入
發現 @Transactional 注解可以自注入解決事務失效的問題,在某次開發中,自然而然想到 @Async 異步是不是也可以自注入解決循環依賴的問題。
NO, NO, NO……
事實告訴我們是不可以的!

從錯誤開始着手:

開始往上面反推 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 自調用不可以,因為在后面初始化階段被代理修改了對象。
@Transactional 為什么可以呢?


先判斷 InfrastructureAdvisorAutoProxyCreator true 生成一個代理對象。

事務的處理器 PersistenceExceptionTranslationPostProcessor 也沒有執行。
繼續 Debug 關注 applyBeanPostProcessorsAfterInitialization

執行結束,發現 Bean 沒有發生改變。
總結
- @Transactional: 是在循環依賴從二級緩存升到三級緩存的時候已經生成了代理對象。
- @Async: 是在初始化階段(initializeBean)去生成代理對象。然后 @Async 導致后面判斷
exposedObject == bean為 false ,從而拋出異常。

可以看出圖中有兩處會執行 BeanPostProcessor :
- 在 singletonFactory.getObject 時,如果是 SmartInstantiationAwareBeanPostProcessor 的子類會執行 getEarlyBeanReference 方法。
- 在 initializeBean 的 applyBeanPostProcessorsAfterInitialization 時會執行所有 BeanPostProcessor 的 postProcessAfterInitialization 的方法。
也有其他的地方在執行后置處理器,比如 applyBeanPostProcessorsBeforeInitialization ,只不過這里關注這倆處。
而這兩處都有可能生成代理對象, @Transactional 是在 getEarlyBeanReference 處生成的代理對象,所以后面判斷 Bean 是否被改變時為 true,而 @Async 是在后面異步生成了代理對象,所以判斷不通過。
至此,分析完畢,錯誤之處,歡迎指正。
