Spring核心思想之 AOP:如何影響DI並引入三級快取解決DI中涉及代理的問題

池塘里洗澡的鸭子發表於2024-03-13

  Spring中AOP的實現與在Spring核心思想之 AOP:在自定義容器基礎上實現AOP功能中實現的自定義AOP一樣,採用後置處理器方式。在Spring的核心思想之DI:詳解Spring DI迴圈依賴實現機制文中末尾提到了一個問題,為什麼是三級快取而不是二級。

  下面示例AOP是如何影響DI的?

          

  AService和BService依賴注入,如果A沒有後置處理器相關操作,AService和BService如上圖就完成了bean生成。然而如果存在後置處理器呢?類似於下圖:

            

  BService注入AService後,系統就會自動提供一個名為 AsyncAnnotationBeanPostProcessor 的處理器,在這個處理器中會生成一個代理的 AService 物件,並用這個物件代替原本的 AService。關鍵在於:原本的 AService 和新生成的代理的 AService 是兩個不同的物件,佔兩塊不同的記憶體地址!

  此時就產生了一個問題:BService中注入的AService與最終的AService不一致!!!下面就是Spring提供的三級快取的方案:

            

  建立一個 AService 的時候,透過反射剛把原始的 AService 建立出來之後,先去判斷當前一級快取中是否存在當前 Bean,如果不存在,則:

    •   首先向三級快取中新增一條記錄,記錄的 key 就是當前 Bean 的 beanName,value 則是一個 Lambda 表示式 ObjectFactory,透過執行這個 Lambda 可以給當前 AService 生成代理物件。

    •   然後如果二級快取中存在當前 AService Bean,則移除掉。

  現在繼續去給 AService 各個屬性賦值,結果發現 AService 需要 BService,然後就去建立 BService,建立 BService 的時候,發現 BService 又需要用到 AService。於是就先去一級快取中查詢是否有 AService,如果有,就使用;如果沒有,則去二級快取中查詢是否有 AService,如果有,就使用;如果沒有,則去三級快取中找出來那個 ObjectFactory,然後執行這裡的 get("AService")方法。關鍵操作就在這個方法中:

    在執行的過程中,會去判斷是否需要生成一個代理物件,如果需要就生成代理物件返回,如果不需要生成代理物件,則將原始物件返回即可。最後,把拿到手的物件存入到AService二級快取中以備下次使用,同時刪除掉三級快取中對應的資料。這樣 BService 所依賴的AService 就建立好了(不管是原始的還是代理物件都在二級快取中了)。

  接下來繼續去完善 AService,去執行各種後置的處理器,此時,有的後置處理器想給 AService 生成代理物件,發現 AService 已經是代理物件了,就不用生成了,直接用已有的代理物件去代替 AService 即可。

  所以得出之前文章中的結論:三級快取的使用將AOP提前操作了。

相關文章