Spring IoC源碼分析(五)

一奕塑、回顧

上回講到spring在容器啟動(dòng)時(shí)需要?jiǎng)?chuàng)建一些單例bean械姻,創(chuàng)建單例bean的過(guò)程實(shí)際上就是spring創(chuàng)建bean實(shí)例的過(guò)程悍引,來(lái)回顧一下上次的代碼,不用全部看完恩脂,找到這次需要講到的createBeanInstance(beanName, mbd, args)方法即可

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

        // BeanWrrapper,Bean包裝器趣斤,簡(jiǎn)單理解成對(duì)bean賦值的俩块,后面展開(kāi)
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            //若mbd為單例,需要先判斷是否為FactoryBean
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        //如果instanceWrapper為空浓领,則創(chuàng)建一個(gè)bean實(shí)例
        if (instanceWrapper == null) {
            //createBeanInstance玉凯,創(chuàng)建bean實(shí)例封裝到wrapper中
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        //通過(guò)wrapper獲取到了bean
        final Object bean = instanceWrapper.getWrappedInstance();
        //處理bean類型
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        // 允許post-processors修改mbd
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                 //簡(jiǎn)單來(lái)說(shuō)就是對(duì)mbd做一些加工  
                 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    //拋出異常
                    ......
                }
                mbd.postProcessed = true;
            }
        }
        // 解決循環(huán)依賴的問(wèn)題
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            ......
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
        // bean在實(shí)例化后,還需要賦值和初始化(init)
        Object exposedObject = bean;
        try {
            //這一步負(fù)責(zé)屬性裝配镊逝,關(guān)鍵就在于BeanWrapper
            populateBean(beanName, mbd, instanceWrapper);
            //處理 bean 初始化完成后的各種回調(diào)
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            //拋出異常
            ......
        }
        //主要用于解決循環(huán)引用壮啊,這部分先跳過(guò)吧
        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()) {
                        //拋出異常
                        ......
                    }
                }
            }
        }
        // 注冊(cè)bean為使用后即銷毀
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            //拋出異常
            ......
        }
        return exposedObject;
}

二嫉鲸、createBeanInstance(beanName, mbd, args)

這個(gè)方法一看就很好理解撑蒜,創(chuàng)建bean實(shí)例,發(fā)現(xiàn)傳入了beanName,bean定義以及相關(guān)的參數(shù)用于執(zhí)行構(gòu)造函數(shù)座菠,跳轉(zhuǎn)到這個(gè)方法看一下

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 檢查class被load
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        //檢查beanClass
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }
        //由supplier提供bean實(shí)例
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }
        //由工廠方法創(chuàng)建bean實(shí)例
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // 這里表示創(chuàng)建已創(chuàng)建過(guò)的bean狸眼,判斷是通過(guò)無(wú)參構(gòu)造函數(shù),還是有參構(gòu)造函數(shù)依賴注入來(lái)完成實(shí)例化
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }
    
        // 下面是第一次實(shí)例化bean的情況浴滴,首先判斷是否采用有參構(gòu)造函數(shù)
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // 有參構(gòu)造函數(shù)依賴注入并實(shí)例化bean
        ctors = mbd.getPreferredConstructors();
        if (ctors != null) {
            return autowireConstructor(beanName, mbd, ctors, null);
        }

        // 無(wú)參構(gòu)造函數(shù)實(shí)例化bean
        return instantiateBean(beanName, mbd);
}

三拓萌、bean的實(shí)例化

其實(shí)可以發(fā)現(xiàn),bean最終的實(shí)例化無(wú)非就是通過(guò)無(wú)參構(gòu)造方法或者有參構(gòu)造方法創(chuàng)建的即通過(guò)autowireConstructor方法和instantiateBean方法升略,由于前者的代碼很長(zhǎng)微王,以后有機(jī)會(huì)會(huì)專門寫一篇來(lái)講,這次先來(lái)看看后者instantiateBean

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
        try {
            Object beanInstance;
            final BeanFactory parent = this;
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                        getInstantiationStrategy().instantiate(mbd, beanName, parent),
                        getAccessControlContext());
            }
            else {
                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
            }
            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            initBeanWrapper(bw);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
        }
}

不難發(fā)現(xiàn)bean是由getInstantiationStrategy().instantiate這一行關(guān)鍵代碼實(shí)現(xiàn)的品嚣,先來(lái)看看InstantiationStrategy是何方神圣

public interface InstantiationStrategy {
/**
 * 默認(rèn)的構(gòu)造方法
 */
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)throws BeansException;

/**
 * 指定構(gòu)造方法
 */

Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
        Constructor<?> ctor, Object... args) throws BeansException;
        
/**
 * 通過(guò)指定的工廠方法
 */
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
        @Nullable Object factoryBean, Method factoryMethod, Object... args)
        throws BeansException;

簡(jiǎn)單來(lái)說(shuō)炕倘,InitiationStrategy提供了一系列通過(guò)構(gòu)造器來(lái)初始化bean實(shí)例的策略。

挑選默認(rèn)的構(gòu)造方法來(lái)看看spring是如何實(shí)現(xiàn)的把

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // Don't override the class with CGLIB if no overrides.
    //如果沒(méi)有方法被覆蓋,通過(guò)BeanUtils#instantiateClass來(lái)初始化(實(shí)質(zhì)是利用反射來(lái)創(chuàng)建)
    if (!bd.hasMethodOverrides()) {
        Constructor<?> constructorToUse;
        //加鎖
        synchronized (bd.constructorArgumentLock) {
            //獲取構(gòu)造方法constructorToUse
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                //獲取Bean的class的對(duì)象
                final Class<?> clazz = bd.getBeanClass();
                //如果clazz是接口類型的,直接拋BeanInstantiationException異常
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    //在當(dāng)前系統(tǒng)安全模式的情況下
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(
                                (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    }
                    //獲取構(gòu)造方法
                    else {
                        constructorToUse = clazz.getDeclaredConstructor();
                    }
                    //將constructorToUse賦給resolvedConstructorOrFactoryMethod屬性
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        //通過(guò)BeanUtils直接使用構(gòu)造器對(duì)象實(shí)例化Bean對(duì)象
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        //生成CGLIB創(chuàng)建的子類對(duì)象
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末翰撑,一起剝皮案震驚了整個(gè)濱河市罩旋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌眶诈,老刑警劉巖涨醋,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異逝撬,居然都是意外死亡浴骂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門宪潮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)靠闭,“玉大人,你說(shuō)我怎么就攤上這事坎炼±颍” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵谣光,是天一觀的道長(zhǎng)檩淋。 經(jīng)常有香客問(wèn)我,道長(zhǎng)萄金,這世上最難降的妖魔是什么蟀悦? 我笑而不...
    開(kāi)封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮氧敢,結(jié)果婚禮上日戈,老公的妹妹穿的比我還像新娘。我一直安慰自己孙乖,他們只是感情好浙炼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布份氧。 她就那樣靜靜地躺著,像睡著了一般弯屈。 火紅的嫁衣襯著肌膚如雪蜗帜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天资厉,我揣著相機(jī)與錄音厅缺,去河邊找鬼。 笑死宴偿,一個(gè)胖子當(dāng)著我的面吹牛湘捎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播窄刘,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼消痛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了都哭?” 一聲冷哼從身側(cè)響起秩伞,我...
    開(kāi)封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欺矫,沒(méi)想到半個(gè)月后纱新,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡穆趴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年脸爱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片未妹。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡簿废,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出络它,到底是詐尸還是另有隱情族檬,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布化戳,位于F島的核電站单料,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏点楼。R本人自食惡果不足惜扫尖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掠廓。 院中可真熱鬧换怖,春花似錦、人聲如沸蟀瞧。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至兆览,卻和暖如春屈溉,著一層夾襖步出監(jiān)牢的瞬間塞关,已是汗流浹背抬探。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帆赢,地道東北人小压。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像椰于,于是被迫代替她去往敵國(guó)和親怠益。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345