六、核心容器 - 註冊單例 Bean 實例、SingletonBeanRegistry 簡介

楓林晚粥 發佈 2022-12-05T17:17:41.768969+00:00

前言上篇文章我們對註冊 Bean 的核心類 BeanDefinitionRegistry 進行了討論,這裡的註冊 Bean 是指保存 Bean的相關信息,也就是將 Bean 定義成 BeanDefinition,然後放入容器中。

前言

上篇文章我們對註冊 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 也是在該類中解決循環依賴問題,這部分也會在後面詳細討論。

關鍵字: