三級緩存
在 Spring 中,Bean 的創建過程涉及到三級緩存。這三級緩存分別是 singletonObjects、earlySingletonObjects 和 singletonFactories。它們在 Spring 容器啟動時用于存儲正在創建的 Bean 實例。
在 Spring 源碼中,三級緩存涉及到了 DefaultSingletonBeanRegistry
類。這個類是 Spring 容器中負責管理單例 Bean 的注冊表,其中包含了三級緩存的實現。下面是 DefaultSingletonBeanRegistry
中與三級緩存相關的源碼片段:
public abstract class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {// 一級緩存:singletonObjectsprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二級緩存:earlySingletonObjectsprivate final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// 三級緩存:singletonFactoriesprivate final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);...protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 從一級緩存中獲取 Bean 實例Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 從二級緩存中獲取 Bean 實例singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 從三級緩存中獲取 Bean 實例的 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 使用 ObjectFactory 創建 Bean 實例singletonObject = singletonFactory.getObject();// 將創建好的 Bean 實例放入二級緩存中this.earlySingletonObjects.put(beanName, singletonObject);// 從三級緩存中移除 ObjectFactorythis.singletonFactories.remove(beanName);}}}}return singletonObject;}...}
在 DefaultSingletonBeanRegistry
類中,singletonObjects
用于存儲已經完成初始化的 Bean 實例,earlySingletonObjects
用于存儲尚未完成初始化的 Bean 實例,singletonFactories
用于存儲創建 Bean 的工廠對象。在 getSingleton()
方法中,首先會嘗試從一級緩存 singletonObjects
中獲取 Bean 實例,如果找不到且 Bean 正在創建中,則會從二級緩存 earlySingletonObjects
中獲取 Bean 實例,如果仍然找不到且允許早期引用,則會從三級緩存 singletonFactories
中獲取 Bean 實例的工廠對象,并使用工廠對象創建 Bean 實例,然后將創建好的 Bean 實例放入二級緩存 earlySingletonObjects
中。
-
singletonObjects:
- 這是最常見的單例對象緩存。當容器創建 Bean 時,會首先嘗試從 singletonObjects 緩存中獲取已經創建好的 Bean 實例。
- 如果能夠從 singletonObjects 中獲取到 Bean 實例,就直接返回該實例。
- 如果 singletonObjects 緩存中不存在 Bean 實例,則繼續后續的創建流程。
-
earlySingletonObjects:
- 這個緩存用于存儲尚未完成初始化的早期單例對象。
- 在創建 Bean 的過程中,如果發現 Bean 的初始化依賴其他 Bean,而這些依賴的 Bean 正好是單例的,則會暫時將正在創建的 Bean 實例放入 earlySingletonObjects 緩存中,以便解決循環依賴的問題。
- 等到 Bean 的創建完成后,會將其移動到 singletonObjects 緩存中。
-
singletonFactories:
- 這個緩存用于存儲創建 Bean 的工廠對象(ObjectFactory)。
- 當 Bean 的創建過程中需要解決循環依賴時,會將創建 Bean 的工廠對象放入 singletonFactories 緩存中。
- 當需要獲取正在創建的 Bean 的依賴時,會從 singletonFactories 緩存中獲取對應的工廠對象,然后通過工廠對象創建 Bean 的代理對象,并將代理對象放入 earlySingletonObjects 緩存中,以便解決循環依賴的問題。
這三級緩存在 Spring 容器啟動時起到了至關重要的作用,它們協同工作以解決 Bean 的循環依賴問題,確保容器能夠正確地創建和管理 Bean 實例。
循環依賴
循環依賴是指兩個或多個 Bean 之間相互依賴形成的循環引用關系。在 Spring 中,循環依賴通常出現在以下場景中:
-
構造器注入循環依賴: 當兩個或多個 Bean 在它們的構造器中相互依賴時,就會出現構造器注入的循環依賴。例如,BeanA 的構造器參數依賴于 BeanB,而 BeanB 的構造器參數又依賴于 BeanA。
-
setter 方法注入循環依賴: 當兩個或多個 Bean 在它們的 setter 方法中相互依賴時,就會出現 setter 方法注入的循環依賴。例如,BeanA 的某個屬性依賴于 BeanB,而 BeanB 的某個屬性又依賴于 BeanA。
為了解決循環依賴的問題,Spring 使用了三級緩存的機制。這個機制的原理如下:
-
當容器創建 Bean 的過程中,如果發現循環依賴,會將正在創建的 Bean 實例放入到早期單例對象的緩存中(即二級緩存
earlySingletonObjects
)。 -
同時,為了解決循環依賴,會創建 Bean 的工廠對象(即 ObjectFactory),并將工廠對象放入到三級緩存
singletonFactories
中。 -
當需要解決循環依賴時,容器會從三級緩存
singletonFactories
中獲取 Bean 的工廠對象,并使用工廠對象創建 Bean 的代理對象。 -
創建好的代理對象會被放入到二級緩存
earlySingletonObjects
中,以便在后續的 Bean 創建過程中能夠獲取到已經創建的 Bean 的代理對象。 -
當所有 Bean 都創建完成后,容器會再次遍歷二級緩存
earlySingletonObjects
中的 Bean 實例,將它們初始化并放入一級緩存singletonObjects
中。
通過三級緩存的機制,Spring 能夠解決循環依賴的問題,確保容器能夠正確地創建和管理 Bean 實例。這種機制下,即使存在循環依賴,也能夠保證所有 Bean 都能夠正確地初始化和注入依賴。