?Spring 創(chuàng)建對象
在上一章我們對invokeBeanFactoryPostProcessors的重要部分進行了詳細的介紹猪腕,總算到了我們的Spring創(chuàng)建對象的過程了,本章會接著前面的refresh進行續(xù)寫。
registerBeanPostProcessors(beanFactory)
這個方法的特性和invokeBeanFactoryPostProcessors(beanFactory);其實差不太多,也是對后置處理器的一些操作潮峦,但這個方法的重量缺少了很多,相信讀者有了invokeBeanFactoryPostProcessors(beanFactory);的經(jīng)驗應該能夠自行理解其基本意義勇婴。
initMessageSource();
初始化國際化資源忱嘹,這里只是對一些資源加載的方式進行規(guī)范。
initApplicationEventMulticaster();
創(chuàng)建ApplicationEventMulticaster這么一個類耕渴,這個類是事件操控的核心拘悦,我們先跳過,這里不會影響整體Bean初始化
onRefresh();
空方法
registerListeners
注冊監(jiān)聽器
finishBeanFactoryInitialization(beanFactory)
總算到我們真正創(chuàng)建Bean的核心方法了橱脸,通過這個方法的名字就可以猜到础米,這就是我們Spring用來創(chuàng)建對象的核心方法,如果不相信的話我們在這里調(diào)試一下添诉,首先看第一張圖
singletonObjects就是我們的實例對象屁桑,這里不同的Spring版本可能singletonObjects所在的類會有一些區(qū)別,那么如果singletonObjects數(shù)量發(fā)生改變說創(chuàng)建對象就是在這里實現(xiàn)的栏赴,我們調(diào)試一下
可以看到singletonObjects的數(shù)量確實增加了幾個蘑斧,而且這幾個就是我們所創(chuàng)建的,那么我們就開始對其進行分析须眷,在對finishBeanFactoryInitialization深度分析時竖瘾,筆者只會對一些核心點進行解釋說明,因為內(nèi)容確實太多柒爸,有些比較特殊的我就一筆帶過准浴,話不多說看代碼
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 這里不知道CONVERSION_SERVICE_BEAN_NAME有什么用
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
?
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
//檢查Spring中是否存在類型轉(zhuǎn)換
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
?
// 禁止使用臨時類加載器進行類型匹配
beanFactory.setTempClassLoader(null);
?
// Allow for caching all bean definition metadata, not expecting further changes.
//允許緩存所有的bean的定義數(shù)據(jù)
beanFactory.freezeConfiguration();
?
// Instantiate all remaining (non-lazy-init) singletons.
//重點,準備bean實例
beanFactory.preInstantiateSingletons();
}
注釋比較詳細捎稚,這里其實沒做什么事情乐横,核心方法是beanFactory.preInstantiateSingletons();我們點進去
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
//拿到所有的bd名字
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
?
// Trigger initialization of all non-lazy singleton beans...
//循環(huán)并判斷是不是不是懶加載的求橄,是不是FactoryBean,然后對bd進行bean創(chuàng)建
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
?
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
這里首先執(zhí)行RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);將我們的BeanDefinition合并葡公,最后都采用RootBeanDefinition聲明罐农,然后判斷是不是單例對象,是不是FactoryBean,如果不是就會進入getBean(beanName);我們在跟進
這里為什么是GetBean而不是創(chuàng)建對象催什,其實 Spring在很多地方都會獲取對象涵亏,所以不可能每次獲取都是創(chuàng)建對象,而應該是先查詢有沒有蒲凶,再創(chuàng)建就像我們使用的緩存技術一樣气筋。我們繼續(xù)
進入這句代碼:Object sharedInstance = getSingleton(beanName);
這里先簡單分析下,如果獲取的對象是沒有完全創(chuàng)建的旋圆,那么的singletonObject為空宠默,isSingletonCurrentlyInCreation(beanName)也會為false那么判斷會退出,記住這個isSingletonCurrentlyInCreation灵巧,然后我們繼續(xù)
這些都不重要搀矫,我們往下看----
Bean實例化
這里的return createBean(beanName, mbd, args);是表達式語法,其實就是一個回調(diào)方式刻肄,然后我們調(diào)試進入getSingleton瓤球,
這里會做一些判斷,如果沒有實例化這個對象那么
它就會執(zhí)行這段代碼beforeSingletonCreation(beanName);我們看看這段代碼做了什么
他會將我們的對象標識為正在創(chuàng)建敏弃,記住這個標識
然后再往下走回走到singletonObject = singletonFactory.getObject();
可以看到這里產(chǎn)生回調(diào)卦羡,不熟悉函數(shù)式的朋友們可以先忽略它,我們進入createBean(beanName, mbd, args);
前面都不重要权她,可以看到創(chuàng)建對象的代碼在這一行Object beanInstance =
這里筆者認為設計的有些累贅了虹茶,它的目的其實就是如果程序員定義的對象實現(xiàn)這個InstantiationAwareBeanPostProcessor接口,那么Spring就會認為這個對象不需要經(jīng)過Spring的完整生命周期隅要,需要脫離Spring管理的意思蝴罪,然后直接return掉,但我想Spring可能也是為了擴展的開放性吧步清,畢竟Spring的設計考慮的十分周全要门。好了,我們回到代碼Object beanInstance = doCreateBean(beanName, mbdToUse, args);
這里定義了一個instanceWrapper廓啊,讀者可以將其當做一個有一些功能的對象欢搜,然后進入instanceWrapper = createBeanInstance(beanName, mbd, args);
這里主要是獲取class類型,然后判斷是不是FactoryMethod創(chuàng)建對象谴轮,如果不是就繼續(xù)往下:
這里其實是一種緩存技術炒瘟,如果我們在前面已經(jīng)確認了這個類的構造器是什么,那么久不會再進行下文的構造器策略第步,直接調(diào)用構造器方法疮装,當然我們這里暫時沒有缘琅。
這里是Spring對實例構造器的一個策略,我們都知道一個類創(chuàng)建一個對象無非就兩種情況廓推,調(diào)用有參構造函數(shù)或者無參構造函數(shù)刷袍,那么我們先從無參構造說起,看下圖
假如我們的ctors為空 也就是說我們的對象是用的無參構造樊展,那么會執(zhí)行到return instantiateBean(beanName, mbd);呻纹,我們跟蹤此代碼
在跟蹤beanInstance =getInstantiationStrategy().instantiate(mbd, beanName, parent);->return BeanUtils.instantiateClass(constructorToUse);->
最終可以看到我們的反射代碼newInstance。介紹完無參構造器創(chuàng)建對象后专缠,我們開始探討第二種有參構造創(chuàng)建對象的方式雷酪,回到IDEA,首先我們對User1類新增一個有參構造器藤肢,
然后我們開始debug調(diào)試太闺,我們以User1類作為調(diào)試類
然后進入determineConstructorsFromBeanPostProcessors方法
這里會拿出很多后置處理器,但前面的基本都是默認實現(xiàn)嘁圈,真正干活的是這個類AutowiredAnnotationBeanPostProcessor
然后進入:
前面的方法是檢查是否存在LOCKUP方法,我們這里沒有執(zhí)行下一步
這里也沒做什么事情蟀淮,只是想從緩存中拿出有沒有確定好的構造器最住,后面會獲取所有構造方法,判斷方法是不是加了@Awtowire注解怠惶,基本都會跳過涨缚,我們直接跳到核心代碼
這里其實就是確認構造器,從我們的斷點來看策治,當我們拿到的構造函數(shù)只有一個脓魏,且參數(shù)大于0,從我們目前的情況來看是符合的通惫,那么就會返回我們構造器茂翔。拿到構造器后我們再看
我們會拿到我們所創(chuàng)建的構造器,那如果我們換一種方式采用多個構造器
返回的值為null履腋,其實這也很好理解珊燎,在沒有指定某個構造器primary時,如果我們創(chuàng)建多個構造器遵湖,Spring不知道如何決策悔政,就只執(zhí)行默認構造器
autowireConstructor()->autowireConstructor()谋国;
這里我們思考下如何用有參構造的方式創(chuàng)建對象,首先是不是確定我們的類迁沫,其次是不是需要確定構造器芦瘾,然后我們還需要確定參數(shù)的值是什么捌蚊,那么下面的操作就是確定參數(shù)的值到底是什么,我們回到IDEA:
這里沒什么需要多說的
這里看有沒有緩存,顯然我們沒有
這里的代碼個人認為Spring可能為了防止其他地方復用這段代碼,所以判斷構造器是不是為空
這里autowiring肯定不會false囤热,然后進入有參構造十分關鍵的代碼
通過方法名我們都能大概猜出來這里就是獲取有參構造傳入的參數(shù)值院溺,前面我們說過,確定構造器還需要構造參數(shù)的值才能成功創(chuàng)建一個對象讯嫂,那么我們看這個代碼能否獲取參數(shù)值
那么怎樣才能獲取參數(shù)值呢祈餐,這里筆者會采用兩種方式:第一種方式筆者會改變Spring源碼
擂啥,發(fā)現(xiàn)已經(jīng)有值,然后User1類會創(chuàng)建對象成功帆阳,當然我們?nèi)ジ淖冊创a是不是不太合適啊哺壶,所以采用第二種方式后置處理器,代碼如下:
依舊可以實現(xiàn)有參構造的方式蜒谤,
這里我們返回了我們的對象。
Bean初始化
在創(chuàng)建完對象后萨咳,Spring將會對象進行初始化懊缺,我們跟蹤applyMergedBeanDefinitionPostProcessors這段代碼:
可以看到這又是循環(huán)后置處理器,獲取屬于MergedBeanDefinitionPostProcessor,然后我們繼續(xù)跟蹤bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);在查看這個方法到底會執(zhí)行哪些處理器鹃两,
我們在對其中之一后置處理器點開
其實這里的處理器就是對我們Spring的生命周期的處理遗座,但這里并不會執(zhí)行,而是采用元信息的方式將它保存起來俊扳,好了途蒋,我們繼續(xù)往下看
前面的代碼不重要,我們直接看到addSingletonFactory(beanName, () ->
getEarlyBeanReference(beanName, mbd, bean));
這里會有四個集合馋记,第一個集合是singletonObjects存放單例Bean的号坡,第二個singletonFactories
存放的是ObjectFactory工廠Bean,這個ObjectFactory個人認為和Bean并無太大區(qū)別梯醒,直接間接存取而已宽堆,第三個earlySingletonObjects是提前存儲的對象,最后一個registeredSingletons存放的是BeanName茸习,用來解決排序問題畜隶,好了我們繼續(xù)
接下來可以看到Spring的屬性注入的核心代碼populateBean(beanName, mbd,
instanceWrapper);,在對這段代碼分析之前号胚,我們先修改一下我們的工程籽慢,首先將User2改成
這條調(diào)整的目的是為了演示循環(huán)依賴,好了猫胁,
然后我們重新debug
這里先對User1屬性注入嗡综,我們點進去
這里又有對后置處理器的處理,這里后置處理器的作用是如果你實現(xiàn)了InstantiationAwareBeanPostProcessors的postProcessAfterInstantiation方法杜漠,那么Spring會認為你牛逼,你要自己初始化察净,那我就中斷這個Bean的后續(xù)一切操作驾茴,就等于脫離Spring的生命周期管理,其實這也是可以想到的氢卡,不一定所有的對象都是需要Spring幫我們處理锈至,這里Spring的設計考慮的十分周全,我們回到IDEA
這里有一個重要的屬性叫AutowireMode译秦,為什么說他重要峡捡,我們會在Spring-Mybatis章節(jié)詳細說明,這里先跳過筑悴,因為我們默認的是NO们拙,然后我們進入這里
看方法名能夠大概猜到這里就是屬性注入的關鍵,我們斷點
然后我們直接跳到AutowiredAnnotationBeanPostProcessor阁吝,進入這個方法PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);首先獲取我們的InjectionMetadata砚婆,注入需要的元數(shù)據(jù)
然后->metadata.inject(bean, beanName, pvs);->element.inject(target, beanName, pvs);
field.set(bean, value);懂反射的小伙伴們都知道,我們可以通過Field類對一個類的對象屬性賦值突勇,所以Spring默認也采用的這種方式装盯,那么我們現(xiàn)在有了類坷虑,缺少value,而這個value在元數(shù)據(jù)中已經(jīng)顯示User2類埂奈,所以我們需要拿到User2的對象才行迄损,回到IDEA上面的代碼,其中有一行
然后我們跟蹤下resolveDependency->doResolveDependency->descriptor.resolveCandidate
最終又回到了getBean账磺,也就是說Spring會從工廠里拿芹敌,而這個時候我們的工廠并沒有創(chuàng)建它,所以User2創(chuàng)建對象后依舊會進行進入屬性注入的方法
這個時候我們跳到了User2的屬性注入方法绑谣,然后一樣User2里面有User1這個類党窜,所以又會去獲取User1的對象,但是我們的User1并沒有創(chuàng)建完成借宵,屬于創(chuàng)建中的狀態(tài)幌衣,那么Spring是如何解決的呢?我們繼續(xù)跟蹤代碼
這里的代碼是我們先創(chuàng)建了User1然后屬性注入user2壤玫,這時工廠沒有User2對象豁护,于是創(chuàng)建User2,User2創(chuàng)建完后開始對內(nèi)部的屬性user1注入欲间,這時會跳到上圖楚里,然后我們再跟蹤進去
singletonObject == null 目前是為空的,因為我們的user1還在創(chuàng)建中猎贴,然而這一行代碼我們運行isSingletonCurrentlyInCreation(beanName)
返回的是true班缎,還記我們創(chuàng)建對象時會將對象標識為正在創(chuàng)建嗎?這里就起到了效果她渴,那么if會成立达址,這個時候就會從我們的ObjectFactory獲取,在上文提到過ObjectFactory是間接存取趁耗,
這里會獲取我們前文存儲的生命周期元數(shù)據(jù)满葛,并執(zhí)行
我們用一張圖回顧下我們的循環(huán)依賴
目前對Spring的整體核心源碼基本已經(jīng)告一段落,后面會對AOP罢屈、Spring-Mybatis嘀韧、事物、數(shù)據(jù)來源儡遮、事件等知識結(jié)合面試題的方式進行嵌套描述乳蛾。