? ? getBean對Spring來說说榆,是一個非常重要的方法喉誊,用于實例化對象。比如在獲取BeanProcessor的時候羔挡,就用到了beanFacroty.getBean來獲取BeanProcessor對象洁奈。從doGetBean出發(fā)。
getSingleton
? ? 這邊涉及到了幾個類里面的參數(shù)先提及一下:
? ? singletonObjects:用Map類型的該參數(shù)來存放beanName和bean實例之間的關(guān)系绞灼,bean的生命周期已結(jié)束(一級緩存)利术;
? ? singletonCurrentlyInCreation:正在實例化的單例;
? ? earlySingletonObjects:提前暴露的單例實例低矮,bean的生命周期還未結(jié)束(二級緩存)印叁;
? ? singletonFactories:用Map類型的該參數(shù)來存放beanName和beanFactory之間的關(guān)系(三級緩存);
? ? 先從一級緩存中根據(jù)beanName拿值军掂,如果拿到了就返回轮蜕,沒有拿到的話,先去判斷下beanName代表的實例是否正在創(chuàng)建蝗锥,如果是在創(chuàng)建中跃洛,那就去二級緩存中拿值,如果沒拿到终议,就去三級緩存中根據(jù)beanName獲取到BeanFactory對象税课,通過BeanFactory的getObject拿到實例,然后重新將值賦給二級緩存痊剖,再從三級緩存中移除beanName和其BeanFactory韩玩,如圖1。
????為什么需要這么麻煩設(shè)計三次緩存來獲取實例陆馁,為什么不像自定義Spring一樣只要用一個singletonObjects就能解決獲取實例的問題找颓?是因為我們在使用Spring的過程中,很多時候涉及到了循環(huán)依賴叮贩,本次只講getBean击狮,循環(huán)依賴下一次再講佛析。
? ? 如果getSingleton獲取到了實例,還回去判斷當(dāng)前返回的是不是和工廠相關(guān)的(beanName有“&”前綴)彪蓬,如果是寸莫,但是并不是FactoryBean類型的就會報錯。所以現(xiàn)在的獲取到的實例要么是個正常的bean档冬,要么是工廠bean膘茎。如果是正常的bean就直接返回,如圖2:
????如果是工廠bean酷誓,先去緩存中嘗試獲取bean披坏,如果成功了直接返回,如果不成功盐数,調(diào)用getObjectFromFactoryBean棒拂,如圖3。
????最終還是會通過調(diào)用doGetObjectFromFactoryBean方法里工廠的getObject操作獲取bean實例玫氢,如圖4:
? ? 不過一般第一次getSingleton是獲取不到實例的帚屉,走的是else這條路線:
? ? 接下來就是看是否有父類工廠、dependsOn依賴于其他實例的創(chuàng)建漾峡,有的話要它們先創(chuàng)建涮阔,這邊就不看了。往下看代碼發(fā)現(xiàn)又出現(xiàn)了一個getSingleton方法灰殴,里面有四個比較重要的方法:
1敬特、beforeSingletonCreation
? ? 該方法中有兩個類參數(shù):inCreationCheckExeclusions(排除正在創(chuàng)建檢查的beanName的集合,這個集合目前遇到的比較少牺陶,知道有這個屬性即可)伟阔,以及singletonCurrentlyIncreation(這個集合里的都是正在進(jìn)行實例化的bean,就是實例化還為完成的beanName掰伸,防止bean對象在進(jìn)行循環(huán)依賴引用的時候反復(fù)創(chuàng)建)皱炉。往singletonCurrentlyIncreation中添加正在實例化的beanName。
2狮鸭、singletonFactory.getObject()
? ? 通過工廠創(chuàng)建實例合搅。
3、afterSingletonCreation
? ? 實例化完成后從singletonCurrentlyIncreation中刪除對應(yīng)的beanName歧蕉。
4灾部、addSingleton
? ? 二、三級緩存刪除對應(yīng)的beanName惯退,一級緩存添加beanName和bean實例的對應(yīng)關(guān)系赌髓,再往registeredSingletons添加beanName代表已經(jīng)完成的bean實例化。
-----------------------------------------------------------------------------------------------------------------------------------
createBean
? ? 關(guān)注doCreateBean,如果是單例锁蠕,嘗試用beanName直接從之前的保存在factoryBeanInstanceCache中獲取BeanWrapper夷野,如果不行則調(diào)用createBeanInstnce來創(chuàng)建BeanWrapper(BeanWrapper是對bean的包裝,是bean到BeanDefinition的中間產(chǎn)物荣倾,用來為bean做屬性填充)悯搔。
createBeanInstance
? ? 用于生成BeanWrapper的方法,有三種實現(xiàn):
? ? 1舌仍、如果當(dāng)前BeanDefinition有instanceSupplier屬性妒貌,就以此來生成BeanWrapper,在使用Spring的過程中抡笼,可以通過如圖9所示來使用:
? ? 2苏揣、如果有factory-method屬性黄鳍,調(diào)用instantiateFactoryMethod生成BeanWrapper推姻。
? ? 3、對于沒有上面兩個屬性的框沟,也可以通過構(gòu)造函數(shù)進(jìn)行實例化藏古,分為有參構(gòu)造函數(shù)和無參構(gòu)造函數(shù)。有參構(gòu)造函數(shù)先通過determineConstructorsFromBeanPostProcessors獲取到含有@Autowired注解的構(gòu)造函數(shù)忍燥,然后調(diào)用autowireConstructor生成BeanWrapper拧晕。無參構(gòu)造函數(shù)直接調(diào)用instantiateBean生成BeanWrapper。
applyMergedBeanDefinitionPostProcessors
? ? 用來對類中的注解進(jìn)行裝配梅垄,是通過BeanPostProcessor的postProcessMergedBeanDefinition進(jìn)行裝配厂捞,列舉下面兩個比較重要的實現(xiàn)類:
CommonAnnotationBeanPostProcessor
? ? 這個類中的解析分為兩部分:一個是postProcessMergedBeanDefinition來掃描@PostConstruct和@PreDestory注解;一個是findResourceMetadata來掃描@Resource注解队丝。
postProcessMergedBeanDefinition:先根據(jù)beanType去緩存lifecycleMetadataCache中尋找LifecycleMetadata靡馁,如果未找到則通過buildLifeCycleMetadata找到里面的initMethod和的storyMethods方法,以及類本身机久,會被包裝成LifeCycleMetadata對象臭墨,如圖10,并放入緩存lifeCycleMetadataCache膘盖,如圖11:
然后通過checkConfigMembers對當(dāng)前的BeanDefinition進(jìn)行掃描胧弛,把其中的initMethod和的storyMethod拿出來,放入類參數(shù)checkedInitMethods和checkedDestoryMethods中侠畔,如圖12:
findResourceMetadata和checkedConfigMembers:和上面掃描初始化和銷毀方法一樣结缚,也有一個緩存參數(shù)injectionMetadataCache,如果找不到也是要通過buildResourceMetadata構(gòu)建软棺,將里面有@Resource注解的元素放入injectedElements中掺冠,如圖13,構(gòu)建完后放入緩存,返回InjectionMetadata德崭,如圖14:
????通過checkConfigMembers對當(dāng)前的BeanDefinition進(jìn)行掃描斥黑,把含有@Resource注解的屬性或者方法拿出來,遍歷的就是上一步存到類中的元素集合眉厨,然后放到類參數(shù)checkedElements中锌奴,如圖15:
AutowiredAnnotationBeanPostProcessor
? ? 功能就是用來掃描方法或者屬性上的@Autowired注解,通過buildAutowiringMetadata方法構(gòu)建元數(shù)據(jù)憾股,將其放入injectionMetadataCache緩存中鹿蜀。然后對BeanDefinition進(jìn)行checkConfigMembers掃描,把含有@Autowired注解的屬性或者方法拿出來服球,放到類參數(shù)checkedElements中茴恰,和上述方式差不多,如圖16:
earlySingletonExposure
? ? 用來判斷是否支持進(jìn)行提前暴露操作斩熊,會根據(jù)當(dāng)前BeanDefinition是否單例往枣、是否允許循環(huán)依賴(一般允許),以及在singletonCurrentlyInCreation中是否存在當(dāng)前beanName粉渠,如圖17:
????如果都符合條件分冈,調(diào)用getEarlyBeanReference獲取到提前暴露的實例,并且在三級緩存中添加beanName和單例工廠霸株,移除二級緩存中提前暴露的實例雕沉,如圖18:
populateBean
? ? 這是IOC/DI依賴注入的核心方法,直接拉下來看關(guān)于BeanPostProcessor的應(yīng)用去件,如圖19:
????關(guān)注postProcessProperties方法坡椒,該方法是之前通過postProcessMergedBeanDefinition掃描注解并收集后對其元數(shù)據(jù)執(zhí)行inject方法。以@Autowired為例尤溜,如圖20:
????首先根據(jù)beanName尋找到InjectionMetadata倔叼,通過element.inject方法對已經(jīng)收集到的注解進(jìn)行反射調(diào)用,比如注解在字段上靴跛,則會使用field.set(bean, value)缀雳;在方法上,則會使用method.invoke(bean, arguements)梢睛。
? ? 對于在xml中配置的屬性肥印,如<property>標(biāo)簽內(nèi)部屬性的依賴注入,則是通過下面applyPropertyValues方法實現(xiàn)的绝葡,如圖22深碱,因為現(xiàn)在基于XML配置的很少使用了,就不必去看是怎么添加屬性的藏畅。
initializeBean
? ? 這個方法是在實例化和IOC/DI注入后的操作敷硅,首先是對某些Aware接口的調(diào)用功咒,如圖23:
????然后調(diào)用了applyBeanPostProcessorsBeforeInitialization對類中某些特殊方法的調(diào)用,也是會先通過beanName拿到元數(shù)據(jù)绞蹦,然后通過invoke方法進(jìn)行反射調(diào)用力奋,如圖24:
? ? 再是通過invokeInitMethods方法,對實現(xiàn)了InitializingBean的類中的afterProperties方法的調(diào)用:
? ? 最后調(diào)用applyBeanPostProcessorsAfterInitialization方法幽七,和before一樣景殷,進(jìn)行反射調(diào)用。
registerDisposableBeanIfNecessary
????在bean創(chuàng)建完成后都會調(diào)用這個方法澡屡,因為用到的都是單例模式的猿挚,所以直接看如下代碼:
? ? DisposableBeanAdapter對象是來負(fù)責(zé)bean銷毀的類,在new的時候會去掃描BeanDefinition中的destory-method屬性驶鹉,以及其余屬性來構(gòu)建對象绩蜻,然后以beanName為key,生成的DisposableBeanAdapter對象為value室埋,放進(jìn)disposableBeans中办绝。
----------------------------------------------------------------------------------------------------------------------------------
getObjectForBeanInstance
? ? 里面有個BeanFactoryUtils.isFactoryDereference方法,判斷傳進(jìn)去的name是否攜帶了“&”作為name開頭词顾,只有工廠beanName才會有這種結(jié)構(gòu)八秃,但如果該實例不是FactoryBean碱妆,還是會拋出異常肉盹。如果沒有攜帶“&”作為name的開頭,并且不是FactoryBean疹尾,表明這是個普通實例上忍,直接返回;如果是工廠實例纳本,則需要調(diào)用getObject從工廠中生產(chǎn)實例后返回窍蓝,上面已經(jīng)有類似的流程了,就不截圖了繁成。
-----------------------------------------------------------------------------------------------------------------------------------
Prototype作用域的BeanDefinition
? ? 邏輯和單例的差不多吓笙,但是不像單例這么復(fù)雜,需要考慮重復(fù)創(chuàng)建的問題巾腕;多例作用域只要執(zhí)行了createBean面睛,就是一個新的實例,如圖27:
-----------------------------------------------------------------------------------------------------------------------------------
埋點
? ??在看源碼的過程中我們經(jīng)匙鸢幔看到如圖28所示的代碼叁鉴,可以看出BeanPostProcessor接口類型是對具有某種特定功能的埋點,根據(jù)對當(dāng)前的BeanPostProcessor進(jìn)行instanceof判斷佛寿,用來過濾掉功能不相關(guān)的BeanPostProcessor幌墓,然后執(zhí)行特定的方法。
下面來看一下有哪些地方用到了這類埋點:
1、MergedBeanDefinitionPostProcessor:圖28調(diào)用的方法是postProcessorMergedBeanDefinition常侣,收集@Resource蜡饵、@PostConstruct、@PreDestory胳施、@Autowired验残、@Value注解的方法和屬性。
2巾乳、SmartInstantiationAwareBeanPostProcessor:調(diào)用的方法是determineCandidateConstructors您没,用來獲取@Autowired注解的方法和屬性;而在循環(huán)依賴中解決bean提前暴露的實例胆绊,則是通過getEarlyBeanReference氨鹏,如圖29:
3、InstantiationAwareBeanPostProcessor:調(diào)用的方法是postProcessorAfterInstantiation压状,其中的continueWithPropertyPopulation為true代表可以進(jìn)行依賴注入仆抵;postProcessProperties則是IOC/DI依賴注入的inject方法的埋點,如圖30: