《系列二》-- 8、單例bean的創建

閱讀之前要注意的東西:本文就是主打流水賬式的源碼閱讀,主導的是一個參考,主要內容需要看官自己去源碼中驗證。全系列文章基於 spring 源碼 5.x 版本。

寫在開始前的話:

閱讀spring 源碼實在是一件龐大的工作,不說全部內容,單就最基本核心部分包含的東西就需要很長時間去消化了:

  • beans
  • core
  • context

實際上我在博客裏貼出來的還只是一部分內容,更多的內容,我放在了個人,fork自 spring 官方源碼倉了; 而且對源碼的學習,必須是要跟着實際代碼層層遞進的,不然只是乾巴巴的文字味同嚼蠟。

https://gitee.com/bokerr/spring-framework-5.0.x-study

這個倉設置的公共倉,可以直接拉取。



Spring源碼閱讀系列--全局目錄.md



1 源碼入口概述

不管是何種作用域的bean 創建,最終都會指向: “如何從零開始創建bean”,而這個話題前文已經講解過了。

本文重點介紹,單例作用域的bean 在這個過程中的動作有何異同。

img2222222.png

這裏顯然是定義了一個回調操作:

sharedInstance 聲明的類型是 Object

Object sharedInstance;

看 sharedInstance 的定義,重點看它的第二個參數,經典匿名內部類寫法。這裏 createBean() 接收 了bean 相關配置信息;

當在 getSingleton(beanName, ObjectFactory) 方法內部調用 ObjectFactory 的 getObject() 方法時,這些參數將會真正登場。

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
    public Object getObject() throws BeansException {
        try {
            // 準備完成後回調  由子類 AbstractAutowireCapableBeanFactory 實現方法
            return createBean(beanName, mbd, args);
        } catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            // 出錯,單例工廠銷燬該 bean
            destroySingleton(beanName);
            throw ex;
        }
    }
});

接下來我們先看看 getSingleton(beanName, ObjectFactory) 幹了什麼:

2 getSingleton(beanName, ObjectFactory) 的行爲

口頭挨個介紹過於乾巴巴了,下邊直接貼出加了註釋的代碼:


/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 *
 * @param beanName         the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 *                         with, if necessary
 * @return the registered singleton object
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 獲得單例對象池的鎖 [排他性], 其它線程想要獲取該對象池的鎖,只能等待
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) { // 新創建bean,單例對象池中不存在,否則直接方法返回
            if (this.singletonsCurrentlyInDestruction) { // bean 已經被廢棄,不能再加載它,拋異常退出
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                                "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            // 進行bean重複創建的校驗,如果當前bean已經在創建流程中拋異常,衆所周知單例bean必須唯一
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 校驗通過後,調用 ObjectFactory 的 getObject() 進一步回調 createBean() 方法
                singletonObject = singletonFactory.getObject();
                // 有沒有覺得這也太簡單了?其實不然,bean 加載的重頭戲還在後邊: createBean() 
                newSingleton = true;
            } catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            } catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            } finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // bean 首次加載後再次校驗,它是否是真的第一次被加載
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 如果是一個新的單例bean,那麼把它假如緩存中,從這裏進去看到的一定會是:三級緩存
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

總結

針對單例作用域bean 的創建,這裏會根據緩存進行判斷,需要保證全局唯一。

  1. getSingleton() 返回 sharedInstance時,實際上最終得到的是回調: createBean()的返回結果

  2. sharedInstance 就只可能有兩種類型: 普通bean 或者 FactoryBean

然後進入如下邏輯,根據 sharedInstance 提取實際的bean

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章