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提前操作了。