1. 程式人生 > >Spring(六)核心容器 - 註冊單例 Bean 例項、SingletonBeanRegistry 簡介

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 也是在該類中解決迴圈依賴問題,這部分也會在後面詳細討論