今天來聊一聊關於 Spring 為什麼使用三級緩存的問題,先説結果哈,Spring框架中的三級緩存主要用於解決循環依賴問題,特別是在單例Bean的創建過程中。
下面V哥會解釋為什麼Spring需要三級緩存,而不是僅僅使用兩級的原因。
- 一級緩存(Singleton Objects):存儲已經完全初始化好的單例Bean。當一個Bean被成功創建並注入到其他Bean中後,它會被放入一級緩存中。
- 二級緩存(Early Singleton Objects):存儲已經完成了BeanNameAware、BeanFactoryAware等Aware接口的回調,但是還沒有完全初始化的Bean。這個緩存主要用於存放早期引用的Bean,這些Bean在完成屬性填充和初始化方法調用之前,就可以被其他Bean引用。
- 三級緩存(Singleton Factories):存儲Bean工廠對象(BeanFactory)創建Bean實例的工廠信息。這個緩存是為了解決構造器循環依賴問題。當Spring容器創建一個Bean時,如果這個Bean的構造器依賴於其他Bean,Spring會首先嚐試創建這個Bean的實例,這個實例的引用會被放入三級緩存中。然後,Spring會嘗試創建依賴的Bean,如果依賴的Bean也存在循環依賴,Spring會從三級緩存中獲取Bean的早期引用,而不是再次創建一個新的實例。
為什麼需要三級緩存:
- 解決循環依賴:在Spring中,如果兩個或多個Bean相互依賴對方的構造器,就會發生循環依賴。兩級緩存無法解決這個問題,因為它們都是在Bean實例化之後才被使用。三級緩存允許在Bean實例化過程中就提供對其他Bean的引用,從而打破循環依賴。
- 優化性能:通過使用三級緩存,Spring可以在Bean實例化階段就解決循環依賴問題,避免了額外的Bean創建嘗試,從而提高了性能。
- 保持Bean的創建過程的原子性:三級緩存確保了Bean的創建過程是原子性的,即在Bean完全初始化之前,不會將其暴露給其他Bean。
- 支持延遲初始化:三級緩存允許Spring在Bean完全初始化之前,就能夠提供Bean的引用,這支持了延遲初始化的模式,即只有在Bean被實際使用時才進行初始化。
總而言之,言而總之,強調一下這句話:三級緩存是Spring框架解決循環依賴問題的關鍵機制,它允許在Bean的創建過程中提供對其他Bean的引用,同時保持了Bean創建的原子性和性能。
三級緩存使用案例
下面V 哥來一個簡單的使用案例,展示如何通過Spring的三級緩存機制解決循環依賴,方便兄弟們更好的理解。
首先,定義兩個Bean,它們在構造器中相互依賴:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ClassA {
private ClassB classB;
@Autowired
public ClassA(ClassB classB) {
this.classB = classB;
}
// ClassA的其他方法...
}
@Component
public class ClassB {
private ClassA classA;
@Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
// ClassB的其他方法...
}
在這個例子中,ClassA和ClassB通過構造器相互注入,形成了循環依賴。如果沒有Spring的三級緩存機制,這種情況會導致異常,因為Spring無法完成其中一個Bean的創建。
Spring框架內部是如何處理這個問題的呢?下面來介紹一下Spring容器創建這兩個Bean時的大致步驟,深入理解一下:
- Spring容器開始創建
ClassA的Bean實例,並將其放入三級緩存singletonFactories中。 - 容器嘗試注入
ClassB到ClassA的構造器中。由於ClassB還沒有完全創建,Spring會嘗試創建ClassB。 - 在創建
ClassB時,容器發現ClassB的構造器需要一個ClassA的實例。由於ClassA已經在三級緩存中,Spring會使用這個早期引用來注入ClassB。 - 一旦
ClassB被創建,它會被放入二級緩存earlySingletonObjects中,並完成剩餘的初始化步驟。 - 然後,容器繼續完成
ClassA的創建和初始化,將其放入一級緩存singletonObjects中。
這樣的話,即使存在循環依賴,Spring也能夠通過三級緩存機制確保每個Bean都能被正確創建和注入,原來如此。
兄弟們可以移步 Spring 源碼,結合這個示例再深入學習,實際的Spring實現會更復雜一些。其實,咱們在使用Spring的的時候,通常不需要直接操作這些緩存,因為Spring容器會自動處理這些邏輯。到這,你應該知道Spring如何解決循環依賴的問題了,完事,下課。