20--Spring實(shí)例化單例bean的準(zhǔn)備工作

上一節(jié)分析了Spring從緩存中獲取單例bean的過程瘾敢,相對于創(chuàng)建一個(gè)全新的單例bean葫盼,該過程還是很簡單的,本節(jié)接著分析創(chuàng)建單例bean的準(zhǔn)備工作。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly)
            throws BeansException {

    // 1徐矩、轉(zhuǎn)換bean的名稱,去掉&前綴,且如果bean有別名的話,優(yōu)先使用別名
    final String beanName = transformedBeanName(name);
    Object bean;

    // 2、從緩存中獲取bean
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    // 3叁幢、如果未能從緩存中獲取到bean,則要重新創(chuàng)建bean
    else {
        // Fail if we're already creating this bean instance: We're assumably within a circular reference.
        // 3.1判斷指定的原型模式的bean是否當(dāng)前正在創(chuàng)建(在當(dāng)前線程內(nèi)),如果是->則拋出異常(Spring不會解決原型模式bean的循環(huán)依賴)
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        // 3.2 檢測bean definition是否存在beanFactory中
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // 如果當(dāng)前BeanFactory中不包含給定beanName的beanDefinition定義,且父beanFactory不為空,則去父beanFactory中再次查找
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 3.3 將name轉(zhuǎn)換為原始beanName
            //     因?yàn)檫@里的name已經(jīng)經(jīng)過beanName的規(guī)范處理,例如:&myBean-->規(guī)范-->myBean
            //     所以當(dāng)我們再次去父beanFactory查找時(shí),要將beanName再次轉(zhuǎn)換為原始的beanName,myBean-->回轉(zhuǎn)-->&myBean
            String nameToLookup = originalBeanName(name);
            // 3.4 下面會遞歸調(diào)用各種getBean的方法重載,從當(dāng)前bean的父factoryBean中加載bean
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                // 參數(shù)不為空,則委托parentBeanFactory使用顯式參數(shù)調(diào)動
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                // 參數(shù)為空,則委托parentBeanFactory使用標(biāo)準(zhǔn)的getBean方法獲取bean
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                // 否則委托parentBeanFactory使用默認(rèn)的getBean方法
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

        // 3.3 如果當(dāng)前bean不是用于類型檢查,則將該bean標(biāo)記為已經(jīng)被創(chuàng)建或者即將被創(chuàng)建
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            // 3.4 合并beanDefinition,如果指定的bean是一個(gè)子bean的話,則遍歷其所有的父bean
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 校驗(yàn)合并的beanDefinition,如果驗(yàn)證失敗,則拋出異常
            checkMergedBeanDefinition(mbd, beanName, args);

            // 3.5 確保初始化當(dāng)前bean所依賴的bean滤灯。
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                // 循環(huán)所有的依賴bean,并遞歸實(shí)例化
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 注冊依賴
                    registerDependentBean(dep, beanName);
                    try {
                        // 實(shí)例化依賴的bean
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // 3.6 創(chuàng)建單例bean
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 創(chuàng)建bean
                        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.
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            // 創(chuàng)建原型模式bean
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

在到達(dá)步驟3.6之前的工作,都是為創(chuàng)建當(dāng)前單例bean的準(zhǔn)備工作曼玩。其中包括了:對BeanDefinition的檢測鳞骤、如果當(dāng)前BeanFactory中不包含BeanDefinition則對父BeanFactory的檢測、BeanDefinition的合并黍判、依賴bean的初始化等等工作豫尽。

1.創(chuàng)建單例bean
// 3.6 創(chuàng)建單例bean
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            // 創(chuàng)建bean
            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.
            destroySingleton(beanName);
            throw ex;
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
  • getSingleton方法分析
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        // 1、嘗試從緩存中獲取bean
        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!)");
            }
            // 2顷帖、創(chuàng)建bean之前的回調(diào)方法
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 3美旧、通過getObject創(chuàng)建bean的實(shí)例
                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.
                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;
                }
                // 4、創(chuàng)建bean之后的回調(diào)方法
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 5贬墩、將新創(chuàng)建的單例bean加入緩存
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

該方法中完成了對單例bean的創(chuàng)建工作榴嗅,并在創(chuàng)建bean之前和之后進(jìn)行方法回調(diào)進(jìn)行一些異常信息的檢查,最后將單例bean加入緩存中震糖。其中關(guān)鍵的步驟就是第三步
通過getObject創(chuàng)建bean的實(shí)例录肯,singletonObject = singletonFactory.getObject();,這里初學(xué)者閱讀起來可能稍微有些繞吊说,singletonFactory.getObject();方法執(zhí)行后會回到3.6中的return createBean(beanName, mbd, args)论咏;完成對bean的創(chuàng)建。

  • createBean方法分析
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {

    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.
    // 確保此時(shí)bean類已經(jīng)被解析颁井,并且在動態(tài)解析類不能存儲在共享合并bean定義中時(shí)克隆bean定義厅贪。
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // 準(zhǔn)備和驗(yàn)證配置的方法注入
    // 注意:這里處理的是replace-method和lookup-method方法注入,而不是@Override注解
    try {
        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.
        // 讓beanPostprocessor有機(jī)會返回一個(gè)代理而不是目標(biāo)bean實(shí)例。
        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 {
        // 執(zhí)行bean創(chuàng)建,并返回bean的實(shí)例
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}

從方法名上好像已經(jīng)接觸到了IoC的核心-->bean的創(chuàng)建雅宾,但是很遺憾养涮,該方法中依然只是例行檢查工作,真正的創(chuàng)建方法在doCreateBean中眉抬,從這里也能看出spring代碼閱讀的一個(gè)小技巧贯吓,真正干活兒的往往是doXXX開頭的方法,而在doXXX之前都是做一些準(zhǔn)備工作蜀变。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悄谐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子库北,更是在濱河造成了極大的恐慌爬舰,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寒瓦,死亡現(xiàn)場離奇詭異情屹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)杂腰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門垃你,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人喂很,你說我怎么就攤上這事蜡镶。” “怎么了恤筛?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵官还,是天一觀的道長。 經(jīng)常有香客問我毒坛,道長望伦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任煎殷,我火速辦了婚禮屯伞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豪直。我一直安慰自己劣摇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布弓乙。 她就那樣靜靜地躺著末融,像睡著了一般钧惧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勾习,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天浓瞪,我揣著相機(jī)與錄音,去河邊找鬼巧婶。 笑死乾颁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的艺栈。 我是一名探鬼主播英岭,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼湿右!你這毒婦竟也來了诅妹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤诅需,失蹤者是張志新(化名)和其女友劉穎漾唉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堰塌,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赵刑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了场刑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片般此。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖牵现,靈堂內(nèi)的尸體忽然破棺而出铐懊,到底是詐尸還是另有隱情,我是刑警寧澤瞎疼,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布科乎,位于F島的核電站,受9級特大地震影響贼急,放射性物質(zhì)發(fā)生泄漏茅茂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一太抓、第九天 我趴在偏房一處隱蔽的房頂上張望空闲。 院中可真熱鬧,春花似錦走敌、人聲如沸碴倾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跌榔。三九已至异雁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矫户,已是汗流浹背片迅。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工残邀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皆辽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓芥挣,卻偏偏與公主長得像驱闷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子空免,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容