spring 知識整理(四):spring bean初始化過程

接著上文器瘪,來看下DefaultListableBeanFactorygetBean過程翠储。

BeanFactory有幾個getBean的重載方法。但在DefaultListableBeanFactory中橡疼,這些重載方法最終會調用AbstractBeanFactory類的一個doGetBean方法援所。

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
    return doGetBean(name, null, args, false);
}

追蹤doGetBean方法

下面的縮減的代碼

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    final String beanName = transformedBeanName(name);
    Object bean;
    //從緩存中獲取單例
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }else {
        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);
            // 創(chuàng)建單例的bean
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }else if (mbd.isPrototype()) {
                // 創(chuàng)建原型的bean
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }else{
                //其他類型
            }
        }catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
    return (T) bean;
}

從上面代碼可以看出spring在getBean的時候主要做了兩個操作:

  • 從緩存中獲取Bean對象
  • 若緩存中不存在Bean對象,則執(zhí)行創(chuàng)建bean的操作

為了弄清流程欣除,我們還是先弄懂spring單例的創(chuàng)建過程住拭。

spring單例的創(chuàng)建過程

從上面的代碼可以抽取一下創(chuàng)建單例的代碼。

sharedInstance = getSingleton(beanName, () -> {
    try {
        return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
        destroySingleton(beanName);
        throw ex;
    }
});

從上面可以看出历帚,創(chuàng)建單例的時候主要是調用了getSingleton的方法滔岳,該方法第一個參數是beanName,第二個參數是一個ObjectFactory挽牢,從名字上就可以看出來谱煤,ObjectFactory主要是用來創(chuàng)建對象的。而這個ObjectFactory主要也是調用AbstractAutowireCapableBeanFactorycreateBean方法禽拔。createBeanbeanName刘离、RootBeanDefinitionarg傳輸進去睹栖。好硫惕,先看看getSingleton的代碼

getSingleton方法

getSingleton方法是AbstractBeanFactory的父類DefaultSingletonBeanRegistry中的方法。DefaultSingletonBeanRegistry從名字可以看出主要是為了單例而創(chuàng)建的野来。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) { //加鎖
        //從緩存中獲取對象
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            //緩存中獲取不到對象恼除,則開始創(chuàng)建對象
            //判斷容器是否在銷毀,若是在銷毀曼氛,則直接跑一次豁辉。
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,"");
            }
            //創(chuàng)建前校驗,主要是檢查排除的bean和把beanName放到singletonsCurrentlyInCreation的map中去
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                //通過ObjectFactory去創(chuàng)建Object
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                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;
                }
                //創(chuàng)建后主要檢查排除的bean和把beanName從singletonsCurrentlyInCreation的map中移除
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                //如果是創(chuàng)建則把生成的對象添加到緩存中去
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

從上面代碼中可以看出搪锣,getSingleton方法主要任務是確保并發(fā)秋忙,確保只創(chuàng)建一個單例,而且具體創(chuàng)建對象還是交給ObjectFactory創(chuàng)建构舟,等對象創(chuàng)建完成后,緩存對象。

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

上面是緩存對象的方法狗超,主要也是把對象放到singletonObjectsregisteredSingleton兩個Map中去弹澎。

再回頭看看createBean方法。

createBean

追蹤下AbstractAutowireCapableBeanFactorycreateBean方法

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
    RootBeanDefinition mbdToUse = mbd;
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
    try {
        //準備prepare方法
        //主要是處理的lookup-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去返回一個代理類,如果不返回代理類則繼續(xù)
        //BeanPostProcessors是只實現InstantiationAwareBeanPostProcessor接口的類竿屹,實現接口的類可以自定義生成自己的bean
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse); //標記1??
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                                   "BeanPostProcessor before instantiation of bean failed", ex);
    }
    try {
        //嗯报强,這里就開始真正創(chuàng)建類了
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(),
                           beanName, "Unexpected exception during bean creation", ex);
    }
}

跟蹤下標記1??中的方法,看看里面到底是怎么回事

resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

再追蹤下applyBeanPostProcessorsBeforeInstantiationapplyBeanPostProcessorsAfterInitialization

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {
    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

原來是給機會BeanPostProcessor和它的子接口InstantiationAwareBeanPostProcessor的機會拱燃,也就是說我們實現這兩個接口的bean就可以處理自己的對象生成規(guī)則了秉溉,666的。

好了碗誉,在深究下doCreateBean方法召嘶,聽說java中do開都的方法都是真正做事的方法

doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        //創(chuàng)建實例的BeanWrapper
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    //從beanWrapper里面獲取包裝類對象
    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.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                //調用MergedBeanDefinitionPostProcessor
                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.
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                      isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        //屬性注入
        populateBean(beanName, mbd, instanceWrapper);
        //進行 init-method初始化,主要是通知各個BeanPostProcessor
        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) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(beanName,  "");
                }
            }
        }
    }
    // Register bean as disposable.
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }
    return exposedObject;
}

doCreateBean方法主要是做了以下事情:

  • createBeanInstance 生成對象哮缺,并返回包裝類
  • popoulateBean 進行屬性注入
  • instantiateBean 進行init-method初始化和后置等處理弄跌,主要是通知各個BeanPostProcessor

總結

貼的代碼有點多,創(chuàng)建對象的一些邏輯還沒深究尝苇,繼續(xù)下去就怕很難閉合了碟绑。倒不如先來個總結。

image
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末茎匠,一起剝皮案震驚了整個濱河市格仲,隨后出現的幾起案子,更是在濱河造成了極大的恐慌诵冒,老刑警劉巖凯肋,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異汽馋,居然都是意外死亡侮东,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門豹芯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悄雅,“玉大人,你說我怎么就攤上這事铁蹈】硐校” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長容诬。 經常有香客問我娩梨,道長,這世上最難降的妖魔是什么览徒? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任狈定,我火速辦了婚禮,結果婚禮上习蓬,老公的妹妹穿的比我還像新娘纽什。我一直安慰自己,他們只是感情好躲叼,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布芦缰。 她就那樣靜靜地躺著,像睡著了一般押赊。 火紅的嫁衣襯著肌膚如雪饺藤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天流礁,我揣著相機與錄音涕俗,去河邊找鬼。 笑死神帅,一個胖子當著我的面吹牛再姑,可吹牛的內容都是我干的。 我是一名探鬼主播找御,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼元镀,長吁一口氣:“原來是場噩夢啊……” “哼斩披!你這毒婦竟也來了睹欲?” 一聲冷哼從身側響起懒叛,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤炕贵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后砰苍,有當地人在樹林里發(fā)現了一具尸體沉噩,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡粘勒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年揭糕,在試婚紗的時候發(fā)現自己被綠了萝快。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡著角,死狀恐怖揪漩,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情吏口,我是刑警寧澤奄容,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布冰更,位于F島的核電站,受9級特大地震影響嫩海,放射性物質發(fā)生泄漏冬殃。R本人自食惡果不足惜囚痴,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一叁怪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧深滚,春花似錦奕谭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至生兆,卻和暖如春难捌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鸦难。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工根吁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人合蔽。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓击敌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拴事。 傳聞我的和親對象是個殘疾皇子沃斤,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內容

  • 1.1 spring IoC容器和beans的簡介 Spring 框架的最核心基礎的功能是IoC(控制反轉)容器,...
    simoscode閱讀 6,713評論 2 22
  • 作者: 一字馬胡 轉載標志 【2017-12-29】 更新日志 日期更新內容備注2017-12-29創(chuàng)建分析文檔...
    一字馬胡閱讀 12,089評論 2 32
  • 1.1 Spring IoC容器和bean簡介 本章介紹了Spring Framework實現的控制反轉(IoC)...
    起名真是難閱讀 2,583評論 0 8
  • 說到菜市場刃宵,最初的印象衡瓶,就是十字路口兩邊的小攤位,總有一些腐爛的菜葉被扔在小攤販的身后牲证。后來城市管理加強哮针,小菜市場...
    耳聆心閱讀 560評論 0 1
  • 如果池莉沒有孩子,她又會是什么樣子从隆〕夏欤看她的作品,孩子是她最大的希望键闺。池莉的作品寿烟,少寫愛情,少寫友情辛燥,寫親情是最多的...
    守夜人MISS閱讀 169評論 0 0