Spring源碼解析(八)-創(chuàng)建單例bean

Spring版本

5.2.5.RELEASE

參考

Spring-IOC-容器源碼分析-創(chuàng)建單例-bean

源碼解析

在上一篇《Spring源碼解析-獲取單例bean》中,在doGetBean的最后,調(diào)用了getSingleton方法,并且將beanName和一個返回createBean方法的匿名方法作為參數(shù)傳入:

sharedInstance = getSingleton(beanName, () -> {
    try {
        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.
        // 在早期的創(chuàng)建過程中解滓,可能為了解決循環(huán)引用問題,導(dǎo)致beanName加入了singleton緩存中兴溜,此時需要移除該緩存
        destroySingleton(beanName);
        throw ex;
    }
});

那么我們先看看getSingleton方法

1. DefaultSingletonBeanRegistry#getSingleton

    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) {
                if (this.singletonsCurrentlyInDestruction) {
                    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 + "'");
                }
                // 寫入singletonsCurrentlyInCreation
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    // 這里的getObject方法實(shí)際上調(diào)用的是singletonFactory匿名函數(shù)的createBean方法
                    singletonObject = singletonFactory.getObject();
                    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.
                    // createBean方法有可能拋出ImplicitlyAppearedSingletonException異常
                    // 該異常是IllegalStateException的子類约啊,當(dāng)這種異常出現(xiàn)的時候耗帕,此時bean可能已經(jīng)被隱含地(implicitly)實(shí)例化
                    // 所以這一步需要再從singletonObjects這個已實(shí)例化的集合匯總獲取一次實(shí)例化對象
                    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;
                    }
                    // 從singletonsCurrentlyInCreation移除
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    // 針對singleton做一些緩存方面的處理,如加入<beanName,bean>的緩存忠售、從早起引用map中移除等
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

首先從緩存中獲取bean實(shí)例传惠,如果存在,直接返回稻扬,否則進(jìn)行創(chuàng)建的流程卦方。
這里面入?yún)?code>singletonFactory是一個函數(shù)式接口參數(shù):

@FunctionalInterface
public interface ObjectFactory<T> {

    /**
     * Return an instance (possibly shared or independent)
     * of the object managed by this factory.
     * @return the resulting instance
     * @throws BeansException in case of creation errors
     */
    T getObject() throws BeansException;

}

因此,singletonFactory.getObject()實(shí)際上就是調(diào)用createBean方法

2. AbstractAutowireCapableBeanFactory#createBean

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        // 確認(rèn)到了這一步bean類型已經(jīng)被解析泰佳,以防動態(tài)解析class的情況下盼砍,mdb的beanClass屬性為空
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            // 處理look-up method和replace method
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // 看英文注釋這里是給BeanPostProcessors一個機(jī)會返回一個代理對象而不是bean實(shí)例
            // 但是resolveBeforeInstantiation內(nèi)部代碼感覺又沒有進(jìn)去執(zhí)行具體邏輯,具體后面解析
            // TODO
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            // 真正創(chuàng)建bean實(shí)例
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            // A previously detected exception with proper bean creation context already,
            // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

1逝她、通過resolveBeanClass解析mdb的beanClass屬性
2衬廷、處理了lookup-method和replace-method倆種注入,關(guān)于這倆種注入方法汽绢,可以戳:14--Spring lookup-method注入和replace-method注入(二)
3、通過resolveBeforeInstantiationBeanPostProcessor一個機(jī)會返回代理對象
4侧戴、最后調(diào)用了doCreateBean進(jìn)行創(chuàng)建

2.1 AbstractAutowireCapableBeanFactory#resolveBeanClass

    @Nullable
    protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
            throws CannotLoadBeanClassException {

        try {
            // 如果mbd已經(jīng)解析出beanClass宁昭,直接返回
            if (mbd.hasBeanClass()) {
                return mbd.getBeanClass();
            }
            if (System.getSecurityManager() != null) {
                return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
                    doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
            }
            else {
                // 否則,進(jìn)行解析邏輯
                return doResolveBeanClass(mbd, typesToMatch);
            }
        }
        catch (PrivilegedActionException pae) {
            ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (ClassNotFoundException ex) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }
        catch (LinkageError err) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
        }
    }
  • mbd已經(jīng)有beanClass酗宋,那么直接返回
  • 否則积仗,調(diào)用doResolveBeanClass進(jìn)行解析

2.2 AbstractAutowireCapableBeanFactory#doResolveBeanClass

    @Nullable
    private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
            throws ClassNotFoundException {

        ClassLoader beanClassLoader = getBeanClassLoader();
        ClassLoader dynamicLoader = beanClassLoader;
        boolean freshResolve = false;

        if (!ObjectUtils.isEmpty(typesToMatch)) {
            // When just doing type checks (i.e. not creating an actual instance yet),
            // use the specified temporary class loader (e.g. in a weaving scenario).
            ClassLoader tempClassLoader = getTempClassLoader();
            if (tempClassLoader != null) {
                dynamicLoader = tempClassLoader;
                freshResolve = true;
                if (tempClassLoader instanceof DecoratingClassLoader) {
                    DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                    for (Class<?> typeToMatch : typesToMatch) {
                        dcl.excludeClass(typeToMatch.getName());
                    }
                }
            }
        }

        // 獲取文本類型的className,通過className和classLoader來獲取beanClass
        String className = mbd.getBeanClassName();
        if (className != null) {
            // 貌似是解析SPEL表達(dá)式的蜕猫,這塊沒看懂
            Object evaluated = evaluateBeanDefinitionString(className, mbd);
            // 如果倆者不相同寂曹,說明使用了SPEL表達(dá)式
            if (!className.equals(evaluated)) {
                // A dynamically resolved expression, supported as of 4.2...
                if (evaluated instanceof Class) {
                    return (Class<?>) evaluated;
                }
                else if (evaluated instanceof String) {
                    className = (String) evaluated;
                    freshResolve = true;
                }
                else {
                    throw new IllegalStateException("Invalid class name expression result: " + evaluated);
                }
            }
            if (freshResolve) {
                // When resolving against a temporary class loader, exit early in order
                // to avoid storing the resolved Class in the bean definition.
                if (dynamicLoader != null) {
                    try {
                        // dynamicLoader不為空,通過dynamicLoader
                        return dynamicLoader.loadClass(className);
                    }
                    catch (ClassNotFoundException ex) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                        }
                    }
                }
                // 如果dynamicLoader為空回右,通過forName進(jìn)行加載
                return ClassUtils.forName(className, dynamicLoader);
            }
        }

        // Resolve regularly, caching the result in the BeanDefinition...
        // 如果className為空隆圆,進(jìn)行常規(guī)加載(該方法內(nèi)部其實(shí)也是通過ClassUtils.forName(className, classLoader))
        return mbd.resolveBeanClass(beanClassLoader);
    }

獲取string類型的className,加載獲得對應(yīng)的class

1.3 AbstractAutowireCapableBeanFactory#doCreateBean

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        // 單例模型翔烁,則從未完成的 FactoryBean 緩存中刪除
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        // 使用合適的實(shí)例化策略來創(chuàng)建新的實(shí)例:工廠方法渺氧、構(gòu)造函數(shù)自動注入、簡單初始化
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        // 判斷是否需要應(yīng)用后置處理器
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        // 這里是早期引用的邏輯蹬屹,用于解決單例模式的循環(huán)引用侣背,需要滿足一下三個條件:
        // 1、單例模式
        // 2慨默、開啟早期引用
        // 3贩耐、beanName正在創(chuàng)建中(A依賴B,B依賴A厦取,先創(chuàng)建A潮太,發(fā)現(xiàn)依賴B,去創(chuàng)建B虾攻,結(jié)果發(fā)現(xiàn)依賴A消别,又再去創(chuàng)建A)
        // 第三點(diǎn)解釋如下:
        // 情景:A依賴B抛蚤,B依賴A
        // 過程:
        // 1、創(chuàng)建A寻狂,走到這一步岁经,A沒有處于創(chuàng)建中,earlySingletonExposure此時為false蛇券,繼續(xù)往下走缀壤,將A正在創(chuàng)建中寫入singletonsCurrentlyInCreation
        // 2、發(fā)現(xiàn)依賴B纠亚,去創(chuàng)建B
        // 3塘慕、創(chuàng)建B,走到這一步蒂胞,B也沒有處于創(chuàng)建中图呢,同步驟一繼續(xù)往下走
        // 4、發(fā)現(xiàn)依賴A骗随,去創(chuàng)建A
        // 5蛤织、創(chuàng)建A,此時鸿染,A已經(jīng)處于singletonsCurrentlyInCreation了指蚜,此時滿足條件,進(jìn)入if分支
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            // 解決循環(huán)引用涨椒,提前將bean實(shí)例寫入singletonFactories摊鸡、earlySingletonObjects和registeredSingletons
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 填充屬性
            populateBean(beanName, mbd, instanceWrapper);
            // 實(shí)例化bean
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            // addSingletonFactory中已經(jīng)將bean加入earlySingletonObjects中,這里從中獲取
            Object earlySingletonReference = getSingleton(beanName, false);
            // 只有循環(huán)依賴的情況下if分支的條件才會成立
            if (earlySingletonReference != null) {
                // exposedObject初始賦值便是bean蚕冬,那么說明其沒有被initializeBean方法改變
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                // allowRawInjectionDespiteWrapping:是否在循環(huán)依賴的情況下重新整理成原生bean
                // 個人理解是為了解決循環(huán)依賴問題免猾,之前使用了早期引用,
                // 而一旦allowRawInjectionDespiteWrapping為true囤热,那么就將該早期引用替換成原聲bean
                // 不過這里的allowRawInjectionDespiteWrapping是false的情況下else if分支成立
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        // alreadyCreated 不包含dependentBean的情況下if分支成立
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    // 如果alreadyCreated包含任何一個dependentBean掸刊,那么這里if分支成立,此時拋出異常
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            // 注冊bean銷毀邏輯
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

1赢乓、使用createBeanInstance創(chuàng)建一個instanceWrapper忧侧,詳見《Spring源碼解析(九)-創(chuàng)建bean實(shí)例》
2、應(yīng)用后置BeanPostProcessor
3牌芋、解決單例模式下循環(huán)引用的問題
4蚓炬、通過populateBean填充屬性,詳見《Spring源碼解析(十)-填充bean屬性》
5躺屁、通過initializeBean應(yīng)用init-method方法肯夏,詳見《Spring源碼解析(十一)-初始化bean》
6、實(shí)例化depends on對應(yīng)的bean
7、調(diào)用registerDisposableBeanIfNecessary注冊bean的銷毀邏輯驯击,詳見《Spring源碼解析(十二)-注冊bean銷毀邏輯》
8烁兰、返回創(chuàng)建完畢的bean實(shí)例

總結(jié)

創(chuàng)建單例bean的核心都在doCreateBean方法中,該方法分別實(shí)現(xiàn)了創(chuàng)建bean實(shí)例徊都、應(yīng)用BeanPostProcessors沪斟、解決循環(huán)引用問題、填充bean屬性暇矫、應(yīng)用init-method方法主之、實(shí)例化depends on對應(yīng)的bean和注冊bean銷毀邏輯等功能,內(nèi)容較多李根,需要逐個慢慢解析擊破

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末槽奕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子房轿,更是在濱河造成了極大的恐慌粤攒,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囱持,死亡現(xiàn)場離奇詭異夯接,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)洪唐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼蚁,“玉大人凭需,你說我怎么就攤上這事「未遥” “怎么了粒蜈?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長旗国。 經(jīng)常有香客問我枯怖,道長,這世上最難降的妖魔是什么能曾? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任度硝,我火速辦了婚禮,結(jié)果婚禮上寿冕,老公的妹妹穿的比我還像新娘蕊程。我一直安慰自己,他們只是感情好驼唱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布藻茂。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辨赐。 梳的紋絲不亂的頭發(fā)上优俘,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機(jī)與錄音掀序,去河邊找鬼帆焕。 笑死,一個胖子當(dāng)著我的面吹牛森枪,可吹牛的內(nèi)容都是我干的视搏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼县袱,長吁一口氣:“原來是場噩夢啊……” “哼浑娜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起式散,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤筋遭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后暴拄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漓滔,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年乖篷,在試婚紗的時候發(fā)現(xiàn)自己被綠了响驴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡撕蔼,死狀恐怖豁鲤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鲸沮,我是刑警寧澤琳骡,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站讼溺,受9級特大地震影響楣号,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怒坯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一炫狱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剔猿,春花似錦毕荐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽员寇。三九已至,卻和暖如春第美,著一層夾襖步出監(jiān)牢的瞬間蝶锋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工什往, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扳缕,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓别威,卻偏偏與公主長得像躯舔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子省古,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344