Spring(六)核心容器 - 註冊單例 Bean 例項、SingletonBeanRegistry 簡介
前言
上篇文章我們對註冊 Bean 的核心類 BeanDefinitionRegistry 進行了討論,這裡的註冊 Bean 是指儲存 Bean 的相關資訊,也就是將 Bean 定義成 BeanDefinition,然後放入容器中。除此之外,Spring 還提供一個統一操作單例 Bean 例項的類 SingletonBeanRegistry,通過該類可直接對單例 Bean 的例項進行儲存、註冊等操作。
SingletonBeanRegistry
SingletonBeanRegistry 是一個介面,其定義了操作單例 Bean 例項的一些基礎方法:
public interface SingletonBeanRegistry { // 註冊單例 Bean。其實就是將該 Bean 儲存到一個專門儲存單例 Bean 例項的Map中,Key是 beanName,Value是對應的單例 Bean 例項 void registerSingleton(String beanName, Object singletonObject); // 通過 beanName 獲取該單例 Bean 例項 Object getSingleton(String beanName); // 通過 beanName 判斷該單例 Bean 例項是否存在 boolean containsSingleton(String beanName); // 返回所有單例 Bean 的名稱 String[] getSingletonNames(); // 返回已註冊的單例 Bean 例項數量 int getSingletonCount(); // 返回當前使用的單例鎖,主要提供給外部協作者使用 Object getSingletonMutex(); }
這個介面的核心實現類是 DefaultSingletonBeanRegistry,該類不僅實現了這些基礎方法,還針對單例 Bean 擴充套件了許多功能,如:儲存 Bean 之間的依賴關係、儲存 Bean 的包含關係(外部類包含內部類)、獲取 Bean 所處的狀態(正在建立、建立完畢等)、回撥銷燬 Bean 時觸發的 destroy 方法等。
下面是 DefaultSingletonBeanRegistry 類中的核心屬性和方法:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { /********** 1、定義的一些 Map 屬性,用來儲存單例 Bean 例項、 Bean 的依賴關係 **********/ // 快取單例 Bean 例項,Key 是 beanName,Value 是單例 Bean 例項 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 快取 Bean 對應的 ObjectFactory // ObjectFactory 是獲取 Bean 例項的工廠,只不過這裡獲取的 Bean 還未完全例項化,屬於提早暴露的 Bean // 該屬性在解決迴圈依賴時使用,後續會深入討論 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 快取 singletonFactories 屬性中通過 ObjectFactory 建立的 Bean // 該屬性也是在解決迴圈依賴時使用,後續會深入討論 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 儲存已註冊的單例 Bean 名稱 private final Set<String> registeredSingletons = new LinkedHashSet<>(256); // 儲存當前正在建立的 Bean 的名稱 private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 儲存當前從建立檢查中排除的 Bean 的名稱 private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); ... // 當前 Bean 是否處於銷燬狀態 private boolean singletonsCurrentlyInDestruction = false; // 儲存實現了 DisposableBean 介面的 Bean,在銷燬 Bean 時,會回撥該 Bean 中的 destory 方法 private final Map<String, Object> disposableBeans = new LinkedHashMap<>(); // 儲存 Bean 的包含關係,key 是 Bean 的名稱,value 是 Bean 裡面包含的其它 Bean 名稱集合 private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16); // 儲存 Bean 的依賴關係:key 是 Bean 的名稱,value 是依賴於該 Bean 的其它 Bean 名稱集合 private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); // 儲存 Bean 的依賴關係:key 是 Bean 的名稱,value 是該 Bean 所依賴的其它 Bean 名稱集合 private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); /******************************** 2、註冊單例 Bean 例項及對應的例項工廠 ********************************/ // 註冊單例 Bean 例項 @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { Assert.notNull(beanName, "Bean name must not be null"); Assert.notNull(singletonObject, "Singleton object must not be null"); synchronized (this.singletonObjects) { // 通過 beanName 獲取 Map 中對應的單例 Bean 例項 Object oldObject = this.singletonObjects.get(beanName); // 如果不為空,則丟擲異常,因為單例已經存在,無法再次註冊 if (oldObject != null) { throw new IllegalStateException("Could not register object [" + singletonObject + "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound"); } // 為空,則進入 addSingleton 方法 addSingleton(beanName, singletonObject); } } // 快取單例 Bean 例項 protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 將單例 Bean 例項存放至 singletonObjects 集合 this.singletonObjects.put(beanName, singletonObject); // 當 beanName 對應的 Bean 例項已被存放至 singletonObjects 集合時,singletonFactories // 和 earlySingletonObjects 集合則不能再持有 beanName 對應的 ObjectFactory 和例項 // 其中原因會在後續迴圈依賴的文章深入討論 this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); // 儲存 Bean 名稱 this.registeredSingletons.add(beanName); } } // 快取 Bean 對應的 ObjectFactory protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } } /********************************* 3、獲取單例 Bean 例項 *********************************/ @Override public Object getSingleton(String beanName) { // 該方法較為複雜,在後續結合迴圈依賴的場景討論 } ... /***************************** 4、對單例 Bean 例項的基礎操作 *****************************/ // 刪除單例 Bean 例項 protected void removeSingleton(String beanName) { synchronized (this.singletonObjects) { this.singletonObjects.remove(beanName); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.remove(beanName); } } // 判斷 beanName 對應的單例 Bean 例項時候存在 @Override public boolean containsSingleton(String beanName) { return this.singletonObjects.containsKey(beanName); } // 返回所有單例 Bean 的 beanName @Override public String[] getSingletonNames() { synchronized (this.singletonObjects) { return StringUtils.toStringArray(this.registeredSingletons); } } // 返回單例 Bean 例項數量 @Override public int getSingletonCount() { synchronized (this.singletonObjects) { return this.registeredSingletons.size(); } } ... /*************************************** 5、 Bean 的狀態 **************************************/ // beanName 對應的 Bean 是否處於例項化階段 public boolean isCurrentlyInCreation(String beanName) { Assert.notNull(beanName, "Bean name must not be null"); return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName)); } protected boolean isActuallyInCreation(String beanName) { return isSingletonCurrentlyInCreation(beanName); } public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); } // 單例 Bean 例項化前執行,將正要建立的 Bean 加入 singletonsCurrentlyInCreation 集合 protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } // 單例 Bean 例項化後執行,從 singletonsCurrentlyInCreation 集合中移除已建立的 Bean protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } } ... /********************* 6、 儲存 Bean 之間的關係、判斷 Bean 之間的關係 *********************/ // 儲存具有包含關係的 Bean(內部類與外部類) public void registerContainedBean(String containedBeanName, String containingBeanName) { synchronized (this.containedBeanMap) { Set<String> containedBeans = this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8)); if (!containedBeans.add(containedBeanName)) { return; } } registerDependentBean(containedBeanName, containingBeanName); } // 儲存具有依賴關係的 Bean public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName); synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { return; } } synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } } ... /***************************** 7、 銷燬 Bean 的方法 *****************************/ ... }
DefaultSingletonBeanRegistry 類中的屬性及方法雖然很多,但也有規律可循的,大致分為對單例 Bean 例項的操作、管理 Bean 之間關係、針對 Bean 的不同狀態進行操作及銷燬 Bean 的操作。
該類中的核心還是那些 Map,類中的所有方法都是對這些 Map 進行操作,而這些 Map 中儲存的是不同場景下的單例 Bean 。
最後
關於 SingletonBeanRegistry 就介紹到這,其主要還是針對單例 Bean 進行操作,外部呼叫者統一繼承該類操作單例 Bean,其主要呼叫者還是 DefaultListableBeanFactory,前篇文章也說過,這是我們當前上下文環境中使用的 BeanFactory 工廠類,在工廠類中執行 getBean 操作時,會呼叫這些方法,後續會詳細討論 getBean 操作。最後值得注意是,Spring 也是在該類中解決迴圈依賴問題,這部分也會在後面詳細討論