SpringBoot源碼-bean的加載(下)

繼續(xù)搞棺榔,兄弟瓶堕,先別走~~

上一節(jié)講到 doCreateBean()方法,上碼:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        // 先從緩存取
        if (mbd.isSingleton()) {        
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        // 緩存取不到症歇,創(chuàng)建
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    // 將 @Autowired等標記的屬性解析出來捞烟,后續(xù)用
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException("……");
                }
                mbd.postProcessed = true;
            }
        }

        // 是否可以提前暴露使用
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("……");
            }
            // 將bean放入緩存中
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
        Object exposedObject = bean;
        try {
            // 注入屬性
            populateBean(beanName, mbd, instanceWrapper);
            // 初始化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();
            }
        }

        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();
                    }
                }
            }
        }

        // 銷毀bean一些東西
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException();
        }
        return exposedObject;
    }

點開

Object earlySingletonReference = getSingleton(beanName, false);

可以看到

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 一級緩存,存的是完成初始化好的bean
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    // 二級緩存当船,存的是尚未填充屬性的bean對象
    singletonObject = this.earlySingletonObjects.get(beanName);
    if (singletonObject == null && allowEarlyReference) {
        synchronized (this.singletonObjects) {
          singletonObject = this.singletonObjects.get(beanName);
          if (singletonObject == null) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null) {
               // 三級緩存
               ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
               if (singletonFactory != null) {
                   singletonObject = singletonFactory.getObject();
                   this.earlySingletonObjects.put(beanName, singletonObject);
                   this.singletonFactories.remove(beanName);
                }
             }
          }
    }
}
}
   return singletonObject;
}

這個就是spring的三級緩存取bean了。

講了半天默辨,好像還是沒觸及bean的實例化德频,別哭缩幸,站起來繼續(xù)搞钞护!回到doCreateBean() 方法课梳,看createBeanInstance()的實現細節(jié),關鍵代碼:

// 獲取bean的class
Class<?> beanClass = resolveBeanClass(mbd, beanName);

return instantiateBean(beanName, mbd);

進入 instantiateBean(beanName, mbd),看到關鍵代碼:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);

進入 這個instantiate(mbd, beanName, this)氧猬,看到以下兩行代碼:

return BeanUtils.instantiateClass(constructorToUse);

return instantiateWithMethodInjection(bd, beanName, owner);

先看前者,點擊進去:

try {
    ReflectionUtils.makeAccessible(ctor);
    if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
    return KotlinDelegate.instantiateClass(ctor, args);
    }
    else {
        Class<?>[] parameterTypes = ctor.getParameterTypes();
        Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
        Object[] argsWithDefaultValues = new Object[args.length];
        for (int i = 0 ; i < args.length; i++) {
        if (args[i] == null) {
            Class<?> parameterType = parameterTypes[i];
            argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
        }
        else {
            argsWithDefaultValues[i] = args[i];
        }
    }
    return ctor.newInstance(argsWithDefaultValues);
    }
}

就是根據構造函數以及參數new一個對象丛晦。

再來看后者 instantiateWithMethodInjection,核心代碼

Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
    instance = BeanUtils.instantiateClass(subclass);
}
else {
    try {
        Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
        instance = enhancedSubclassConstructor.newInstance(args);
}

這就是實例化的地方,聽說使用cglib瘸爽,可以查查它的資料

以上是new出一個bean的實例,bean的加載還未完成享言,因為還有一些屬性需要注入譬胎《嗫罚回到doCreateBean()方法,填充屬性語句:

populateBean(beanName, mbd, instanceWrapper);

點進去,關鍵代碼:

int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
    }
    if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
    }
            pvs = newPvs;
}

// 將依賴實際注入
applyPropertyValues(beanName, mbd, bw, pvs);

一者是根據名稱注入,一者是根據類型注入拍鲤,注入后,pvs持有這些注入的屬性信息景鼠,然后applyPropertyValues 注入屬性鲫构,點擊該方法昂秃,進去,核心代碼:

bw.setPropertyValues(new MutablePropertyValues(deepCopy));

點進去,一路追蹤到:

for (PropertyValue pv : propertyValues) {
    try {
        setPropertyValue(pv);
    }
}

這就是屬性注入了,屬性注入后,bean就可以使用了驾讲,后面還有一些個性化設置颅停,這里不涉足了纸肉。

收工~~

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末逊移,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子凤瘦,更是在濱河造成了極大的恐慌,老刑警劉巖返吻,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門吊档,熙熙樓的掌柜王于貴愁眉苦臉地迎上來香璃,“玉大人,你說我怎么就攤上這事】勰遥” “怎么了盒至?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么钉凌? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任福青,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘啊片。我一直安慰自己祖驱,他們只是感情好陵像,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妥凳,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死殿衰,一個胖子當著我的面吹牛,可吹牛的內容都是我干的箱硕。 我是一名探鬼主播剧罩,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼舰罚,長吁一口氣:“原來是場噩夢啊……” “哼饲漾!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤狂丝,失蹤者是張志新(化名)和其女友劉穎夕膀,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體美侦,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡产舞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了菠剩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片易猫。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖具壮,靈堂內的尸體忽然破棺而出准颓,到底是詐尸還是另有隱情哈蝇,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布攘已,位于F島的核電站炮赦,受9級特大地震影響,放射性物質發(fā)生泄漏样勃。R本人自食惡果不足惜吠勘,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望峡眶。 院中可真熱鬧剧防,春花似錦、人聲如沸辫樱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狮暑。三九已至鸡挠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間搬男,已是汗流浹背拣展。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留止后,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓溜腐,卻偏偏與公主長得像译株,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子挺益,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容