GetBean源碼全面解讀

GetBean源碼部分

protected??T?doGetBean(finalStringname,@NullablefinalClass?requiredType,

@NullablefinalObject[]?args,?boolean?typeCheckOnly)?throws?BeansException?{

//會包括解析別名等操作

finalStringbeanName?=?transformedBeanName(name);

Objectbean;

//?先檢查單例列表中是否已經注冊了這個bean

ObjectsharedInstance?=?getSingleton(beanName);

if(sharedInstance?!=null&&?args?==null)?{

bean?=?getObjectForBeanInstance(sharedInstance,?name,?beanName,null);

}

else{

//?檢查bean是否并發(fā)被創(chuàng)建

if(isPrototypeCurrentlyInCreation(beanName))?{

thrownewBeanCurrentlyInCreationException(beanName);

}

//?檢查是否在父類工廠中,邏輯和這個差不多,這里省略....

//標記bean正在被創(chuàng)建

if(!typeCheckOnly)?{

markBeanAsCreated(beanName);

}

try{

//合并父類中的方法及屬性,下面會細講??????????????????????

finalRootBeanDefinition?mbd?=?getMergedLocalBeanDefinition(beanName);

//檢查這個bean是否為抽象類

checkMergedBeanDefinition(mbd,?beanName,?args);

//?這里是為了保證獲取的bean的依賴都需要先生成

String[]?dependsOn?=?mbd.getDependsOn();

if(dependsOn?!=null)?{

for(Stringdep?:?dependsOn)?{

if(isDependent(beanName,?dep))?{

thrownewBeanCreationException(mbd.getResourceDescription(),?beanName,

"Circular?depends-on?relationship?between?'"+?beanName?+"'?and?'"+?dep?+"'");

}

registerDependentBean(dep,?beanName);

try{

getBean(dep);

}

catch(NoSuchBeanDefinitionException?ex){

throwex;

}

}

}

//?創(chuàng)建單例的bean,看下方的createBean方法

if(mbd.isSingleton())?{

sharedInstance?=?getSingleton(beanName,?()?->?{

try{

returncreateBean(beanName,?mbd,?args);

}

catch(BeansException?ex)?{

destroySingleton(beanName);

throwex;

}

});

bean?=?getObjectForBeanInstance(sharedInstance,?name,?beanName,?mbd);

}

elseif(mbd.isPrototype())?{

//?It's?a?prototype?->?create?a?new?instance.

ObjectprototypeInstance?=null;

try{

beforePrototypeCreation(beanName);

prototypeInstance?=?createBean(beanName,?mbd,?args);

}

finally{

afterPrototypeCreation(beanName);

}

bean?=?getObjectForBeanInstance(prototypeInstance,?name,?beanName,?mbd);

}

else{

StringscopeName?=?mbd.getScope();

finalScope?scope?=this.scopes.get(scopeName);

if(scope?==null)?{

thrownewIllegalStateException("No?Scope?registered?for?scope?name?'"+?scopeName?+"'");

}

try{

ObjectscopedInstance?=?scope.get(beanName,?()?->?{

beforePrototypeCreation(beanName);

try{

returncreateBean(beanName,?mbd,?args);

}

finally{

afterPrototypeCreation(beanName);

}

});

bean?=?getObjectForBeanInstance(scopedInstance,?name,?beanName,?mbd);

}

catch(IllegalStateException?ex)?{

thrownewBeanCreationException(beanName,

"Scope?'"+?scopeName?+"'?is?not?active?for?the?current?thread;?consider?"+

"defining?a?scoped?proxy?for?this?bean?if?you?intend?to?refer?to?it?from?a?singleton",

ex);

}

}

}

catch(BeansException?ex)?{

cleanupAfterBeanCreationFailure(beanName);

throwex;

}

}

//?檢查需要的類型和實際傳參類型是否一致.?這里省略....

return(T)?bean;

}

整個操作大概是以下幾步:

獲取實際的beanName,其中會處理帶&號前綴的beanName视事,并解析別名讶坯。

檢查單例列表中是否存在該beanName的bean冰悠,若存在則無需走下面的創(chuàng)建bean的流程裹芝。

若單例列表中并不存在此bean咙崎,則檢查是否有并發(fā)創(chuàng)建弟跑。這里的判斷只針對scope為prototype類型的bean廊蜒。

檢查bean是否存在于父類工廠中,若存在胯盯,則走父類工廠的getBean流程懈费。向上委托,保證容器中只會存在一個同名的bean博脑。

標記bean正在被創(chuàng)建憎乙。

如果有父類,這里會遞歸合并父類的方法以及屬性叉趣。并會用自己重寫的方法覆蓋其父類的方法泞边。合并完成并檢查這個bean的是否是抽象類。

如果該bean上有注解@DependsOn,或者配置文件上配置有該屬性,則需保證該bean的所有依賴需要先在容器內注冊疗杉。

分單例和原型以及其他scope類型來創(chuàng)建bean阵谚。

檢查需要的類型和生成的bean類型是否一致。

返回創(chuàng)建好的bean烟具。

getSingleton源碼部分(beanName梢什,allowEarlyReference)

這里的singletonObjects是一個緩存了beanName和bean的Map,若存在,直接返回净赴。

不存在绳矩,則檢查是否這個bean是否正在創(chuàng)建的過程中罩润,先檢查earlySingletonObjects這個容器,這個容器里面放著的是已經構造完成但是沒有注入屬性的對象玖翅,若存在,也會直接返回割以。

嘗試著從singletonFactories中獲取金度,然后調用getObject方法去獲取對象。并將獲取到的對象放到earlySingletonObjects容器中严沥,然后從singletonFactories容器中移除猜极。

這里這么設計是為了解決循環(huán)依賴的問題。若A依賴B消玄,B依賴C跟伏,C又依賴A,這樣三個bean就形成了一個環(huán)(這里只是針對set方法注入的bean,構造器注入還是會有循環(huán)依賴的問題而拋出異常的)翩瓜,spring會將創(chuàng)建的bean實例提前暴露在緩存中受扳,一旦下一個bean創(chuàng)建的時候需要依賴上個bean,則直接使用ObjectFactory來獲取bean兔跌。

這里舉個生活中的例子闡述下:就拿建一個小區(qū)房來說勘高,建房子是一個很復雜的工序,但是咱們只要把架子搭好,告訴大家這塊地是用來建這個房子的就行华望。至于其他裝修蕊蝗,家私等等東西都可以后面再進行補充。咱們不能搭架子的時候去放家具吧赖舟,這樣整個都會亂套蓬戚,也不符合常理。(這里房子的框架是咱們程序中的一個對象A宾抓,家具是另一個對象B碌更,A依賴B,B依賴A)

循環(huán)依賴

相關的邏輯有用到以下代碼段:

每次singleton bean創(chuàng)造之前都會調用的方法洞慎,在singletonsCurrentlyInCreation容器中加入這個bean的beanName,標記這個bean正在創(chuàng)建中痛单,供后期生成ObjectFactory。這里有個inCreationCheckExclusions容器劲腿,在這里我理解為屬于該容器的bean必須要初始化完成才允許被獲取旭绒。也就是說,添加進該容器后bean便不會允許早期的循環(huán)依賴了焦人。

上面的代碼片段的調用在doCreateBean源碼中(排在bean對象創(chuàng)建之后和屬性注入之前)挥吵,可以觀察到要執(zhí)行addSingletonFactory方法需要滿足三個條件:

這個bean是單例的,

允許循環(huán)依賴花椭,

這個bean正在被創(chuàng)建的過程中忽匈。

在滿足這三個條件的情況下,會在singletonFactories容器中緩存一個生成該bean的工廠矿辽,將其提前暴露出去丹允。這里關注下getEarlyBeanReference(beanName, mbd, bean)這個方法,實際上ObjectFactory中getObject方法調用的也是這個方法袋倔。

getMergedBeanDefinition源碼部分

看這部分之前雕蔽,首先得明白BeanDefinition是用來干什么的,這個類會在整個源碼解析過程中出現(xiàn)無數(shù)次宾娜。Spring把BeanDefinition定義成IOC容器的內部數(shù)據結構批狐,實際上它也就是POJO對象在IOC容器中的抽象,通過這個對象前塔,IOC容器能很方便的對Bean進行管理嚣艇,包括利用它進行屬性的注入等等…

protectedRootBeanDefinitiongetMergedBeanDefinition(

String?beanName,?BeanDefinition?bd,?@Nullable?BeanDefinition?containingBd)

throwsBeanDefinitionStoreException

{

synchronized(this.mergedBeanDefinitions)?{

RootBeanDefinition?mbd?=null;

//?重新去獲取一次,有可能該BeanDefinition已經生成

if(containingBd?==null)?{

mbd?=this.mergedBeanDefinitions.get(beanName);

}

if(mbd?==null)?{

if(bd.getParentName()?==null)?{

//?沒有父類則深拷貝一個RootBeanDefinition

if(bdinstanceofRootBeanDefinition)?{

mbd?=?((RootBeanDefinition)?bd).cloneBeanDefinition();

}

else{

mbd?=newRootBeanDefinition(bd);

}

}

else{

//?有父類則需要先獲取父類的BeanDefinition华弓,流程和獲取子類的BeanDefinition一致

BeanDefinition?pbd;

try{

String?parentBeanName?=?transformedBeanName(bd.getParentName());

if(!beanName.equals(parentBeanName))?{

pbd?=?getMergedBeanDefinition(parentBeanName);

}

else{

BeanFactory?parent?=?getParentBeanFactory();

if(parentinstanceofConfigurableBeanFactory)?{

pbd?=?((ConfigurableBeanFactory)?parent).getMergedBeanDefinition(parentBeanName);

}

else{

thrownewNoSuchBeanDefinitionException(parentBeanName,

"Parent?name?'"+?parentBeanName?+"'?is?equal?to?bean?name?'"+?beanName?+

"':?cannot?be?resolved?without?an?AbstractBeanFactory?parent");

}

}

}

catch(NoSuchBeanDefinitionException?ex)?{

thrownewBeanDefinitionStoreException(bd.getResourceDescription(),?beanName,

"Could?not?resolve?parent?bean?definition?'"+?bd.getParentName()?+"'",?ex);

}

//這里進行深拷貝食零,并將子類重寫的方法和屬性進行覆蓋

mbd?=newRootBeanDefinition(pbd);

mbd.overrideFrom(bd);

}

//?若前面沒配置scope類型,這里設置為單例范圍

if(!StringUtils.hasLength(mbd.getScope()))?{

mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);

}

//?這里對內部類做了一些處理该抒,若包含它的bean不是單例的慌洪,則該bean也將不會是單例的

if(containingBd?!=null&&?!containingBd.isSingleton()?&&?mbd.isSingleton())?{

mbd.setScope(containingBd.getScope());

}

//?將生產的BeanDefinition?緩存起來

if(containingBd?==null&&?isCacheBeanMetadata())?{

this.mergedBeanDefinitions.put(beanName,?mbd);

}

}

returnmbd;

}

}

在mergedBeanDefinitions同步的情況下再次讀取緩存顶燕,防止該BeanDefinition已經被合并過了。

檢查是否有父類冈爹,若有父類涌攻,則必須遞歸去合并BeanDefinition。

將子類重寫后的方法覆蓋到定義的BeanDefinition中频伤。

設置scope類型恳谎。

將生成的BeanDefinition緩存起來。

registerDependentBean源碼部分

這一部分應該還是很容易理解的憋肖,這里面出現(xiàn)了兩個Map,一個是dependentBeanMap因痛,它主要用來裝載鍵為beanName值為dependentBeanName的容器,另一個dependenciesForBeanMap是用來裝載鍵為dependentBeanName值為beanName的容器岸更,這樣可以方便我們觀察一個類需要組裝哪些依賴鸵膏,然后這個類同時是哪些類的依賴。

getSingleton源碼部分(beanName怎炊,singletonFactory)

publicObject?getSingleton(String?beanName,?ObjectFactory?singletonFactory)?{

Assert.notNull(beanName,"Bean?name?must?not?be?null");

synchronized?(this.singletonObjects)?{

//先去singletonObjects容器中去獲取谭企,能獲取到就直接返回了

Object?singletonObject?=this.singletonObjects.get(beanName);

if(singletonObject?==null)?{

//調用destroySingletons方法singletonsCurrentlyInDestruction屬性才會變成true

if(this.singletonsCurrentlyInDestruction)?{

thrownew?Exception("xx"));

}

//這里會將beanName緩存到singletonsCurrentlyInCreation集合中

beforeSingletonCreation(beanName);

boolean?newSingleton?=false;

boolean?recordSuppressedExceptions?=?(this.suppressedExceptions?==null);

if(recordSuppressedExceptions)?{

this.suppressedExceptions?=?new?LinkedHashSet<>();

}

try{

//這里會觸發(fā)下面的createBean方法

singletonObject?=?singletonFactory.getObject();

newSingleton?=true;

}

catch(IllegalStateException?ex)?{

//?如果是與此同時被創(chuàng)建了,則直接獲取评肆,如果能獲取到值不為null债查,則正常返回。

//(注意這里捕獲異常正常返回的話就不會走下面的addSingleton方法了瓜挽。)

singletonObject?=this.singletonObjects.get(beanName);

if(singletonObject?==null)?{

throwex;

}

}

catch(BeanCreationException?ex)?{

if(recordSuppressedExceptions)?{

for(Exception?suppressedException?:this.suppressedExceptions)?{

ex.addRelatedCause(suppressedException);

}

}

throwex;

}

finally{

if(recordSuppressedExceptions)?{

this.suppressedExceptions?=null;

}

//這里會將beanName從singletonsCurrentlyInCreation集合中移除

afterSingletonCreation(beanName);

}

if(newSingleton)?{

//添加到singletonObjects和registeredSingletons緩存中盹廷,并從singletonFactories和earlySingletonObjects中移除

addSingleton(beanName,?singletonObject);

}

}

returnsingletonObject;

}

}

直接去singletonObjects中獲取,獲取到了便直接返回久橙。

獲取不到俄占,先將beanName緩存到singletonsCurrentlyInCreation集合中,作為標記表示該bean正在被創(chuàng)建的過程中剥汤。

觸發(fā)createBean方法去創(chuàng)建bean颠放,這里可以去看一下ObjectFactory這個接口工廠,這里是對getObject方法的一個回調(AbstractAutowireCapableBeanFactory中的createBean方法)吭敢。

創(chuàng)建bean的過程中在不出異常的情況下便會進行下圖的操作后并返回,也就操作了幾個容器的緩存而已暮芭。

createBean源碼部分

這一塊不是很復雜鹿驼,復雜的地方在doCreateBean這個方法中。

protectedObjectcreateBean(StringbeanName,?RootBeanDefinition?mbd,@NullableObject[]?args)

throws?BeanCreationException?{

RootBeanDefinition?mbdToUse?=?mbd;

//?要保證RootBeanDefinition的beanClass是存在的

Class?resolvedClass?=?resolveBeanClass(mbd,?beanName);

if(resolvedClass?!=null&&?!mbd.hasBeanClass()?&&?mbd.getBeanClassName()?!=null)?{

mbdToUse?=newRootBeanDefinition(mbd);

mbdToUse.setBeanClass(resolvedClass);

}

//?這一塊沒什么研究辕宏,注解意思是(檢查所有帶有override的方法是否都是存在的)

try{

mbdToUse.prepareMethodOverrides();

}

catch(BeanDefinitionValidationException?ex)?{

}

try{

//這一塊我猜測大概是看咱們自己有提供實例化的方法不畜晰,若有,則不會走下面的doCreateBean方法瑞筐。

Objectbean?=?resolveBeforeInstantiation(beanName,?mbdToUse);

if(bean?!=null)?{

returnbean;

}

}

catch(Throwable?ex)?{

}

try{

//創(chuàng)建bean的真正方法

ObjectbeanInstance?=?doCreateBean(beanName,?mbdToUse,?args);

}

returnbeanInstance;

}

catch(Exception?e){

throwe;

}

}

doCreateBean源碼部分

protectedObjectdoCreateBean(finalStringbeanName,finalRootBeanDefinition?mbd,final@NullableObject[]?args)

throws?BeanCreationException?{

//?Instantiate?the?bean.

BeanWrapper?instanceWrapper?=null;

if(mbd.isSingleton())?{

instanceWrapper?=this.factoryBeanInstanceCache.remove(beanName);

}

if(instanceWrapper?==null)?{

//?創(chuàng)建這個bean,真正構建時有分兩種情況凄鼻,jdk反射和cglib動態(tài)代理

instanceWrapper?=?createBeanInstance(beanName,?mbd,?args);

}

finalObjectbean?=?instanceWrapper.getWrappedInstance();

Class?beanType?=?instanceWrapper.getWrappedClass();

if(beanType?!=?NullBean.class)?{

mbd.resolvedTargetType?=?beanType;

}

//?允許后置處理器來修改這個BeanDefinition

synchronized?(mbd.postProcessingLock)?{

if(!mbd.postProcessed)?{

try{

applyMergedBeanDefinitionPostProcessors(mbd,?beanType,?beanName);

}

catch(Throwable?ex)?{

thrownewBeanCreationException(mbd.getResourceDescription(),?beanName,

"Post-processing?of?merged?bean?definition?failed",?ex);

}

mbd.postProcessed?=true;

}

}

//?用來解決循環(huán)依賴問題的,上面已經有過詳細解釋了】榘觯看上面循環(huán)依賴模塊

boolean?earlySingletonExposure?=?(mbd.isSingleton()?&&this.allowCircularReferences?&&

isSingletonCurrentlyInCreation(beanName));

if(earlySingletonExposure)?{

if(logger.isTraceEnabled())?{

logger.trace("Eagerly?caching?bean?'"+?beanName?+

"'?to?allow?for?resolving?potential?circular?references");

}

addSingletonFactory(beanName,?()?->?getEarlyBeanReference(beanName,?mbd,?bean));

}

//?Initialize?the?bean?instance.

ObjectexposedObject?=?bean;

try{

//進行屬性的注入闰非,調用bean的set方法進行字段的初始化

populateBean(beanName,?mbd,?instanceWrapper);

//進行一些初始化方法的調用,比如afterPropertiesSet等等峭范。

exposedObject?=?initializeBean(beanName,?exposedObject,?mbd);

}

catch(Throwable?ex)?{

if(ex?instanceof?BeanCreationException?&&?beanName.equals(((BeanCreationException)?ex).getBeanName()))?{

throw(BeanCreationException)?ex;

}

}

if(earlySingletonExposure)?{

ObjectearlySingletonReference?=?getSingleton(beanName,false);

if(earlySingletonReference?!=null)?{

if(exposedObject?==?bean)?{

exposedObject?=?earlySingletonReference;

}

//在出現(xiàn)循環(huán)依賴后财松,從earlySingletonObjects中獲取的bean對象和initializeBean后

//的不一致,證明被后置處理器處理過了纱控,前后bean不一致辆毡,需要拋出異常

elseif(!this.allowRawInjectionDespiteWrapping?&&?hasDependentBean(beanName))?{

String[]?dependentBeans?=?getDependentBeans(beanName);

Set?actualDependentBeans?=newLinkedHashSet<>(dependentBeans.length);

for(StringdependentBean?:?dependentBeans)?{

if(!removeSingletonIfCreatedForTypeCheckOnly(dependentBean))?{

actualDependentBeans.add(dependentBean);

}

}

if(!actualDependentBeans.isEmpty())?{

thrownewBeanCurrentlyInCreationException(beanName,

"Bean?with?name?'"+?beanName?+"'?has?been?injected?into?other?beans?["+

StringUtils.collectionToCommaDelimitedString(actualDependentBeans)?+

"]?in?its?raw?version?as?part?of?a?circular?reference,?but?has?eventually?been?"+

"wrapped.?This?means?that?said?other?beans?do?not?use?the?final?version?of?the?"+

"bean.?This?is?often?the?result?of?over-eager?type?matching?-?consider?using?"+

"'getBeanNamesOfType'?with?the?'allowEagerInit'?flag?turned?off,?for?example.");

}

}

}

}

//?注冊bean的銷毀方法

try{

registerDisposableBeanIfNecessary(beanName,?bean,?mbd);

}

catch(BeanDefinitionValidationException?ex)?{

thrownewBeanCreationException(

mbd.getResourceDescription(),?beanName,"Invalid?destruction?signature",?ex);

}

returnexposedObject;

}

doCreateBean大概有以下步驟:

調用createBeanInstance方法初始化bean實例,這里不包括屬性的注入甜害。

調用合并bean的后置處理器修改這個bean的BeanDefinition的一些定義舶掖。即調用MergedBeanDefinitionPostProcessor的實現(xiàn)類的postProcessMergedBeanDefinition方法對BeanDefinition進行一些額外的處理。

為早期的循環(huán)依賴做準備尔店,將包裝了bean的工廠方法塞到singletonFactories中访锻。

調用populateBean方法進行一些屬性的注入。

執(zhí)行initializeBean方法進行一些初始化方法的調用闹获,例如:afterPropertiesSet方法的調用期犬。與此同時,其后置處理器有可能對指定的bean進行增強避诽。

如果出現(xiàn)了bean的增強龟虎,然后又有依賴它的類先生成,則需拋出異常沙庐。例如:對象A被增強了鲤妥,得到A+對象,而此時對象B有依賴對象A拱雏,循環(huán)依賴時通過singletonFactories獲取到的對象卻是增強前的A對象棉安,這時就會出現(xiàn)問題。如果不拋出異常铸抑,spring容器緩存的是A+對象贡耽,但是B引用的卻是A,這樣就會出現(xiàn)不可預測的問題鹊汛。

instantiateBean源碼

這里是createBeanInstance方法中最終調用的方法蒲赂,這里有三個流程:

進行對象的構造,這里關注下CglibSubclassingInstantiationStrategy這個策略類刁憋,有繼承SimpleInstantiationStrategy類滥嘴,調用其instantiate可以調用對象的構造器進行對象的初始化,在BeanDefinition屬性MethodOverrides不存在時至耻,可以用jdk的反射進行獲取對象若皱,否則則必須使用cglib動態(tài)代理镊叁。(這里的MethodOverrides的存在需要對象中某個方法用@Lookup注解修飾,或者XML定義中有 lookup-method屬性

用BeanWrapperImpl對生成的對象進行包裝走触,并激活注冊默認編輯器的屬性晦譬。

注冊默認的編輯器,然后將ConversionService這個類的引用設置到BeanWrapper對象上饺汹。ConversionService是用來進行類型轉換的蛔添,里面的屬性converters用一個map維護著各種類型的轉換器。

populateBean源碼部分

下面關注幾個重點代碼兜辞,省略了一些代碼迎瞧,可以自己去翻閱下:

protectedvoidpopulateBean(String?beanName,?RootBeanDefinition?mbd,?@Nullable?BeanWrapper?bw){

......

PropertyValues?pvs?=?(mbd.hasPropertyValues()???mbd.getPropertyValues()?:null);

if(mbd.getResolvedAutowireMode()?==?AUTOWIRE_BY_NAME?||?mbd.getResolvedAutowireMode()?==?AUTOWIRE_BY_TYPE)?{

MutablePropertyValues?newPvs?=newMutablePropertyValues(pvs);

//?這里是根據bean名稱進行依賴注入的

if(mbd.getResolvedAutowireMode()?==?AUTOWIRE_BY_NAME)?{

autowireByName(beanName,?mbd,?bw,?newPvs);

}

//?這里是根據bean的類型進行依賴注入的

if(mbd.getResolvedAutowireMode()?==?AUTOWIRE_BY_TYPE)?{

autowireByType(beanName,?mbd,?bw,?newPvs);

}

pvs?=?newPvs;

}

......

if(pvs?!=null)?{

//實際上注入屬性值的方法,這里是populateBean方法的重點

applyPropertyValues(beanName,?mbd,?bw,?pvs);

}

}

這里注釋下applyPropertyValues的部分源碼:

protectedvoidapplyPropertyValues(StringbeanName,?BeanDefinition?mbd,?BeanWrapper?bw,?PropertyValues?pvs)?{

MutablePropertyValues?mpvs?=null;

List?original;

if(pvsinstanceofMutablePropertyValues)?{

mpvs?=?(MutablePropertyValues)?pvs;

if(mpvs.isConverted())?{

//?這里可以迅速返回逸吵。當這個PropertyValues對象中的值都是處理過后便可以觸發(fā)凶硅。狀態(tài)值會在下面幾行代碼設置。

try{

bw.setPropertyValues(mpvs);

return;

}

catch(BeansException?ex)?{

thrownewBeanCreationException(

mbd.getResourceDescription(),?beanName,"Error?setting?property?values",?ex);

}

}

original?=?mpvs.getPropertyValueList();

}

else{

original?=?Arrays.asList(pvs.getPropertyValues());

}

TypeConverter?converter?=?getCustomTypeConverter();

if(converter?==null)?{

converter?=?bw;

}

BeanDefinitionValueResolver?valueResolver?=newBeanDefinitionValueResolver(this,?beanName,?mbd,?converter);

//?這里是個深拷貝扫皱,解析所有引用的值足绅。

List?deepCopy?=newArrayList<>(original.size());

boolean?resolveNecessary?=false;

for(PropertyValue?pv?:?original)?{

if(pv.isConverted())?{

deepCopy.add(pv);

}

else{

StringpropertyName?=?pv.getName();

ObjectoriginalValue?=?pv.getValue();

//這里的resolveValueIfNecessary是一個需要關注的方法,有興趣的小伙伴可以點進去看看韩脑,

//里面封裝了針對各種類型的屬性的解析氢妈,例如List,Map,Set等等類型。

ObjectresolvedValue?=?valueResolver.resolveValueIfNecessary(pv,?originalValue);

ObjectconvertedValue?=?resolvedValue;

boolean?convertible?=?bw.isWritableProperty(propertyName)?&&

!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);

if(convertible)?{

convertedValue?=?convertForProperty(resolvedValue,?propertyName,?bw,?converter);

}

//為了避免每次創(chuàng)建都去轉換屬性

if(resolvedValue?==?originalValue)?{

//這里的觸發(fā)條件必須為該屬性得是有寫權限的段多,并且里面不能帶有“.”和“[”這個符號首量,這里我的理解是

//teacher.name以及student[1].name這樣的propertyName便不能觸發(fā)這個條件

if(convertible)?{

pv.setConvertedValue(convertedValue);

}

deepCopy.add(pv);

}

elseif(convertible?&&?originalValueinstanceofTypedStringValue?&&

!((TypedStringValue)?originalValue).isDynamic()?&&

!(convertedValueinstanceofCollection?||?ObjectUtils.isArray(convertedValue)))?{

//這一塊的條件比上一個多了幾個,源值必須是string類型进苍,且不能是動態(tài)的加缘,并且不能是集合和數(shù)組中的任意一個。

pv.setConvertedValue(convertedValue);

deepCopy.add(pv);

}

else{

//條件在這里觸發(fā)后就不會打開快捷返回的開關了

resolveNecessary?=true;

deepCopy.add(newPropertyValue(pv,?convertedValue));

}

}

}

//設置converted狀態(tài)值觉啊,供其組裝屬性時快捷返回拣宏。

if(mpvs?!=null&&?!resolveNecessary)?{

mpvs.setConverted();

}

//?將我們深拷貝出來的值設置到包裝類BeanWrapperImpl包裝的對象上

try{

bw.setPropertyValues(newMutablePropertyValues(deepCopy));

}

catch(BeansException?ex)?{

thrownewBeanCreationException(

mbd.getResourceDescription(),?beanName,"Error?setting?property?values",?ex);

}

}

setPropertyValues方法的源碼最終調用的是AbstractNestablePropertyAccessor類的setPropertyValue方法,在這里BeanWrapperImpl是它的實現(xiàn)類杠人,從名字上看也能猜出來這個類是個處理嵌套屬性的訪問器勋乾。

publicvoidsetPropertyValue(String?propertyName,?@Nullable?Objectvalue)?throws?BeansException{

AbstractNestablePropertyAccessor?nestedPa;

try{

//這里可以解析嵌套的屬性

nestedPa?=?getPropertyAccessorForPropertyPath(propertyName);

}

catch(NotReadablePropertyException?ex)?{

thrownewNotWritablePropertyException(getRootClass(),this.nestedPath?+?propertyName,

"Nested?property?in?path?'"+?propertyName?+"'?does?not?exist",?ex);

}

//這里獲取到了最終解析到的屬性名

PropertyTokenHolder?tokens?=?getPropertyNameTokens(getFinalPath(nestedPa,?propertyName));

//給最終解析到的屬性名賦值操作

nestedPa.setPropertyValue(tokens,newPropertyValue(propertyName,value));

}

上面有個getPropertyAccessorForPropertyPath方法,點進去會發(fā)現(xiàn)他會有個解析“.”和“[]”的方法getNestedPropertySeparatorIndex搜吧,它的作用我舉個例子來說明一下:一個班級有多個學生市俊,我想設置某個學生的名字,班級是個Class對象,里面有屬性:private Student[] students這里我想修改下student[2]的name屬性滤奈,我就必須先用getStudent方法取出 Student[] 數(shù)組,然后再在 Student[] 數(shù)組中找到索引為2的Student撩满,最后修改Student身上的name屬性蜒程。

GetBean流程圖


在此我向大家推薦一個架構學習交流群绅你。交流學習群號:938837867 暗號:555 里面會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis昭躺,Netty源碼分析忌锯,高并發(fā)、高性能领炫、分布式偶垮、微服務架構的原理,JVM性能優(yōu)化帝洪、分布式架構等這些成為架構師必備

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末似舵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子葱峡,更是在濱河造成了極大的恐慌砚哗,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砰奕,死亡現(xiàn)場離奇詭異蛛芥,居然都是意外死亡,警方通過查閱死者的電腦和手機军援,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門仅淑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胸哥,你說我怎么就攤上這事涯竟。” “怎么了烘嘱?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵昆禽,是天一觀的道長。 經常有香客問我蝇庭,道長醉鳖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任哮内,我火速辦了婚禮盗棵,結果婚禮上,老公的妹妹穿的比我還像新娘北发。我一直安慰自己纹因,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布琳拨。 她就那樣靜靜地躺著瞭恰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狱庇。 梳的紋絲不亂的頭發(fā)上惊畏,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天恶耽,我揣著相機與錄音,去河邊找鬼颜启。 笑死偷俭,一個胖子當著我的面吹牛,可吹牛的內容都是我干的缰盏。 我是一名探鬼主播涌萤,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼口猜!你這毒婦竟也來了负溪?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤暮的,失蹤者是張志新(化名)和其女友劉穎笙以,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冻辩,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡猖腕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了恨闪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倘感。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖咙咽,靈堂內的尸體忽然破棺而出老玛,到底是詐尸還是另有隱情,我是刑警寧澤钧敞,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布蜡豹,位于F島的核電站,受9級特大地震影響溉苛,放射性物質發(fā)生泄漏镜廉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一愚战、第九天 我趴在偏房一處隱蔽的房頂上張望娇唯。 院中可真熱鬧,春花似錦寂玲、人聲如沸塔插。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽想许。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伸刃,已是汗流浹背谎砾。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工逢倍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捧颅,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓较雕,卻偏偏與公主長得像碉哑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子亮蒋,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容