目錄
循環依賴問題
三級緩存
三級緩存創建Bean的流程(解決循環依賴問題)
?三級緩存的局限性
Spring的三級緩存是為了解決單例Bean的循環依賴問題而存在的。
循環依賴問題
簡單來說就是A依賴B,而B又依賴A。即創建A的時候,需要先創建B;但是創建B的時候,需要先創建A。這樣就陷入了死循環,兩個都創建不了。
三級緩存
- 一級緩存:存儲已經完全初始化的單例Bean
- 二級緩存:存儲已經實例化但還未初始化的Bean
- 三級緩存:存儲用于創建Bean的工廠
要理解三級緩存創建Bean的邏輯,首先需要了解Bean的生命周期:
- 實例化(分配內存空間)
- 填充屬性值(解析依賴關系,注入默認屬性等)
- 初始化(設置屬性值,執行邏輯等)
- 各種Aware通知,如BeanNameAware、BeanFactoryAware等
- 執行初始化前置方法
- 執行@PostConstruct初始化方法
- 執行初始化后置方法
- 使用Bean
- 銷毀Bean
(當然在實例化之前,還要進行一些實例化前置處理,這里不討論。)
注意:初始化一定是在填充屬性值的后面,否則可能出現異常(如空指針)
三級緩存創建Bean的流程(解決循環依賴問題)
- 創建Bean對象時,首先看一級緩存中是否存在,如果存在,直接使用即可;
- 不存在則實例化一個Bean,并通過三級緩存的工廠進行填充屬性和初始化。
- 如果這個過程存在循環依賴問題,如A需要注入B,Spring就在三級緩存中實例化B,并把B放到二級緩存中;
- A完成初始化后,創建成功,B也可以在二級緩存中完成初始化,并放到一級緩存中。
?三級緩存的局限性
三級緩存僅用來解決單例Bean的循環依賴問題。例如原型Bean的循環依賴就無法通過三級緩存來解決。
如果原型Bean也采用三級緩存的方式,會增加巨大的開銷,因為原型Bean的數量是遠遠多于單例Bean的,而且每個Bean的屬性和狀態都可能有巨大的不同,要存儲這些所有的Bean和對應的工廠,耗費的資源是十分巨大的。雖然可以在一級緩存中移除已經取走的Bean,但是一級緩存是通過一個ConcurrentHashMap來維護的,頻繁的進行移除操作,對性能影響也很大。再者從設計理念上來說,原型Bean是每次創建都獲取到一個新的對象,從緩存中取顯然不滿足這個理念。因此原型Bean的循環依賴問題不適合用三級緩存來解決。事實上,創建原型Bean的時候,如果存在循環依賴的問題,Spring會直接拋異常。
因此在設計上,應該避免使用循環依賴。