Spring Core Container 源码分析三:Spring Beans 初始化流程分析

 2019-11-02 21:22  阅读(1078)
文章分类:Spring boot

前言

本文是笔者所著的Spring Core Container 源码分析系列之一;

本篇文章主要试图梳理出 Spring Beans 的初始化主流程和相关核心代码逻辑;

本文转载自本人的博客,伤神的博客 http://www.shangyang.me/2017/04/01/spring-core-container-sourcecode-analysis-beans-instantiating-process/

本文为作者的原创作品,转载需注明出处;

源码分析环境搭建

参考Spring Core Container 源码分析二:环境准备

测试用例

依然使用这个官网上的用例,来进行调试;

Person.java

| 12345678910111213141516171819202122232425262728293031|packageorg.shangyang.spring.container;/––@authorshangyang/publicclassPerson{Stringname;Personspouse;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicPersongetSpouse(){returnspouse;}publicvoidsetSpouse(Personspouse){this.spouse=spouse;}}| | :-----: | | 12345678910111213141516171819202122232425262728293031|packageorg.shangyang.spring.container;/––@authorshangyang/publicclassPerson{Stringname;Personspouse;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicPersongetSpouse(){returnspouse;}publicvoidsetSpouse(Personspouse){this.spouse=spouse;}} |

beans.xml

| 12345678910111213141516|<beansxmlns=“http://www.springframework.org/schema/beans”xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”xmlns:p=“http://www.springframework.org/schema/p”xsi:schemaLocation=“http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd”><!–传统的方式–><beanname=“john”class=“org.shangyang.spring.container.Person”><propertyname=“name”value=“JohnDoe”/><propertyname=“spouse”ref=“jane”/></bean><beanname=“jane”class=“org.shangyang.spring.container.Person”><propertyname=“name”value=“JaneDoe”/></bean></beans>;| | :-----: | | 12345678910111213141516|<beansxmlns=“http://www.springframework.org/schema/beans”xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”xmlns:p=“http://www.springframework.org/schema/p”xsi:schemaLocation=“http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd”><!–传统的方式–><beanname=“john”class=“org.shangyang.spring.container.Person”><propertyname=“name”value=“JohnDoe”/><propertyname=“spouse”ref=“jane”/></bean><beanname=“jane”class=“org.shangyang.spring.container.Person”><propertyname=“name”value=“JaneDoe”/></bean></beans>; |

| 12345678910111213|@TestpublicvoidtestApplicationContext(){@SuppressWarnings(“resource”)ApplicationContextcontext=newClassPathXmlApplicationContext(“beans.xml”);Personp=context.getBean(“john”,Person.class);assertEquals(“JohnDoe”,p.getName());assertEquals(“JaneDoe”,p.getSpouse().getName());}| | :-----: | | 12345678910111213|@TestpublicvoidtestApplicationContext(){@SuppressWarnings(“resource”)ApplicationContextcontext=newClassPathXmlApplicationContext(“beans.xml”);Personp=context.getBean(“john”,Person.class);assertEquals(“JohnDoe”,p.getName());assertEquals(“JaneDoe”,p.getSpouse().getName());} |

源码分析

备注,这里只针对 Spring 容器实例化singletonbean 的主流程进行介绍;singletonbean 在 Spring 容器中被初始化的特点是,在 Spring 容器的启动过程中就进行初始化;

(最好的分析源码的方式,就是通过高屋建瓴,逐个击破的方式;首先通过流程图获得它的蓝图(顶层设计图),然后再根据蓝图上的点逐个击破;最后才能达到融会贯通,胸有成竹的境界;所以,这里作者用这样的方式带你深入剖析 Spring 容器里面的核心点,以及相关主流程到底是如何运作的。)

主流程

20191102100745\_1.pngbean-creation-overall-process.png

本章节我们将详细去阐述的是,Spring 容器是如何对 Singleton bean 进行初始化并注册到当前容器的;与之相关的主要有两个流程,

  1. 解析 bean definitions 并注册
    解析 bean definitiions 并注册到当前的 BeanFactory 中;此步骤是在step 1.1.1.2 obtainFreshBeanFactory完成;更详细的介绍参考解析并注册 bean definitions 流程
  2. 从 #1 中找到所有的已注册的singletonbean definitions,遍历,实例化得到 Singleton beans;此步骤对应的是 step 1.1.1.11 finishBeanFactoryInitialization 开始进行 singleton bean 的构造过程,其后调用AbstractBeanFactory#getBean(beanFactory)方法进行构造;更详细的介绍参考Do Get Bean流程。

解析并注册 bean definitions 流程

该部分参考新的博文Spring Core Container 源码分析七:注册 Bean Definitions

Do Get Bean 流程

Do Get Bean 流程的入口是AbstractBeanFactory#doGetBean方法,主流程图如下,

20191102100745\_2.png
do-get-bean-process.png

主流程大致为,从缓存中找到是否已经实例化了该singletonbean,如果已经实例化好了,那么就直接返回;如果在缓存中没有找到,则将当前的 bean 封装为RootBeanDefinition,然后通过调用DefaultSingletonBeanRegistry#getSingleton得到初始化好的singletonbean,然后将其注册至缓存(step 1.3.3 addSingleton),然后再判断是普通 bean 还是 factory bean 作必要的处理(step 1.4 getObjectForBeanInstance)后,最后返回;

RootBeanDefinition

初始化了一个RootBeanDefinition对象,正如其类名描述的那样,是该 bean 的顶层描述;包含了 bean 的字段属性,ref属性以及继承相关等等属性;

Step 1.3:DefaultSingletonBeanRegistry#getSingleton

此步骤的相关代码如下,

| 12345678910111213141516171819|//Createbeaninstance.if(mbd.isSingleton()){sharedInstance=getSingleton(beanName,newObjectFactory<Object>(){@OverridepublicObjectgetObject()throwsBeansException{try{returncreateBean(beanName,mbd,args);}catch(BeansExceptionex){//Explicitlyremoveinstancefromsingletoncache:Itmighthavebeenputthere//eagerlybythecreationprocess,toallowforcircularreferenceresolution.//Alsoremoveanybeansthatreceivedatemporaryreferencetothebean.destroySingleton(beanName);throwex;}}});bean=getObjectForBeanInstance(sharedInstance,name,beanName,mbd);}| | :-----: | | 12345678910111213141516171819|//Createbeaninstance.if(mbd.isSingleton()){sharedInstance=getSingleton(beanName,newObjectFactory<Object>(){@OverridepublicObjectgetObject()throwsBeansException{try{returncreateBean(beanName,mbd,args);}catch(BeansExceptionex){//Explicitlyremoveinstancefromsingletoncache:Itmighthavebeenputthere//eagerlybythecreationprocess,toallowforcircularreferenceresolution.//Alsoremoveanybeansthatreceivedatemporaryreferencetothebean.destroySingleton(beanName);throwex;}}});bean=getObjectForBeanInstance(sharedInstance,name,beanName,mbd);} |

调用父类DefaultSingletonBeanRegistry#getSingleton方法;注意,这里通过接口ObjectFactory<Object>定义了一个回调方法getObject(),通过该回调方法调用AbstractAutowireCapableBeanFactory#createBean方法,通过此回调方法正式拉开了实例化 bean 的序幕

Step 1.3.1.1:AbstractAutowireCapableBeanFactory#createBean

AbstractAutowireCapableBeanFactory#doCreateBean 方法是初始化 bean 的最核心的入口方法,执行流程如Do Get Bean 流程所示,

  1. 主流程主要做了这么三件事情,一、instantiate bean;二、populate bean;三、initialize bean
  2. 包含五个子流程,他们分别是factory instantiate beanautwire instantiate beandefault instantiate beanpopulate bean以及initialize bean,其中,前三个子流程对应第一件事情,实例化 bean;其次的子流程populate bean对应的是第二件事情,为 bean 设置 property 参数;最后一个子流程 [initialize bean] 对应最后一件事情既初始化 bean,这里的初始化指的是是对创建好的 bean 做一些修饰动作的。

下面我们分别来分析这三件事情

第一件事情:instantiate bean

该步骤对应Do Get Bean 流程中的Step 1.3.1.1.3.1 createBeanInstance;根据 bean 的不同配置方式,实现了三种实例化 bean 的方式,分别是factory instantiate beanautwire instantiate bean以及default instantiate bean

factory instantiate bean

用工厂方法实例化 bean,待叙;

autwire instantiate bean

通过 autowire 注解的方式实例化 bean,待叙;

default instantiate bean

此步骤对应Do Get Bean 流程中的Step 1.3.1.1.3.1.3 instantiateBean,其对应子流程default instantiate bean如下图所示,

20191102100745\_3.png
default-instantiate-bean-process.png

注意几点

  • 这里仅仅是通过使用其构造函数constructor使用Java 反射实例化了 bean,并没有对其进行任何的参数赋值,赋值过程参考populate bean流程;

  • 将 bean 封装为 BeanWrapper,然后

    • 注册 default PropertyEditor
    • 注册 custom PropertyEditor

最后返回 BeanWrapper

第二件事情:populate bean

对应Do Get Bean 流程中的Step 1.3.1.1.3.4 populateBean,通过调用AbstractAutowireCapableBeanFactory#populateBean正式给 bean 的参数进行赋值;为什么方法名取名为populate呢?查百度翻译,结果是居住于、生活于、移民于、落户于的意思,丝毫没有赋值的意思,但是记得以前和美国人共事的时候,他们非常喜欢用这个词populate,特别是在创建某个对象的时候,他们特别喜欢用这个词;后来无意中发现,populate创建填充的意思,所以,这里的意思就是,填充这个 bean;下面看看 populate bean 的流程图,看看它是怎么玩的,

20191102100745\_4.png
populate-bean-process.png

通过调用AbstractAutowireCapableBeanFactory#applyPropertyValues方法正式给 bean 进行赋值操作,赋值的主流程主要包括两个部分,resolve property value objectset property value to bean

resolve property value

对应上面Sequence Diagram中的Step 1.5 – Step 1.7;这一步主要是去遍历当前 bean 所有的 property,并依次解析(resolve)得到对应的 Java 对象;通过方法BeanDefinitionValueResolver#resolveValueIfNecessary进行解析,解析的过程是针对不同类型的 Property,采用不同的解析方式,里面目前总共对应了十种类型,先看看它的源码,

| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104|publicObjectresolveValueIfNecessary(ObjectargName,Objectvalue){//Wemustcheckeachvaluetoseewhetheritrequiresaruntimereference//toanotherbeantoberesolved.if(valueinstanceofRuntimeBeanReference){//这里表示该beandefinitionref引用的是一个bean,那么这里,必须对该bean进行初始化操作;RuntimeBeanReferenceref=(RuntimeBeanReference)value;returnresolveReference(argName,ref);}elseif(valueinstanceofRuntimeBeanNameReference){StringrefName=((RuntimeBeanNameReference)value).getBeanName();refName=String.valueOf(doEvaluate(refName));if(!this.beanFactory.containsBean(refName)){thrownewBeanDefinitionStoreException(“Invalidbeanname‘”+refName+“‘inbeanreferencefor“+argName);}returnrefName;}elseif(valueinstanceofBeanDefinitionHolder){//ResolveBeanDefinitionHolder:containsBeanDefinitionwithnameandaliases.BeanDefinitionHolderbdHolder=(BeanDefinitionHolder)value;returnresolveInnerBean(argName,bdHolder.getBeanName(),bdHolder.getBeanDefinition());}elseif(valueinstanceofBeanDefinition){//ResolveplainBeanDefinition,withoutcontainedname:usedummyname.BeanDefinitionbd=(BeanDefinition)value;StringinnerBeanName=“(innerbean)”+BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR+ObjectUtils.getIdentityHexString(bd);returnresolveInnerBean(argName,innerBeanName,bd);}elseif(valueinstanceofManagedArray){//Mayneedtoresolvecontainedruntimereferences.ManagedArrayarray=(ManagedArray)value;Class<?>elementType=array.resolvedElementType;if(elementType==null){StringelementTypeName=array.getElementTypeName();if(StringUtils.hasText(elementTypeName)){try{elementType=ClassUtils.forName(elementTypeName,this.beanFactory.getBeanClassLoader());array.resolvedElementType=elementType;}catch(Throwableex){//Improvethemessagebyshowingthecontext.thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,“Errorresolvingarraytypefor“+argName,ex);}}else{elementType=Object.class;}}returnresolveManagedArray(argName,(List<?>)value,elementType);}elseif(valueinstanceofManagedList){//Mayneedtoresolvecontainedruntimereferences.returnresolveManagedList(argName,(List<?>)value);}elseif(valueinstanceofManagedSet){//Mayneedtoresolvecontainedruntimereferences.returnresolveManagedSet(argName,(Set<?>)value);}elseif(valueinstanceofManagedMap){//Mayneedtoresolvecontainedruntimereferences.returnresolveManagedMap(argName,(Map<?,?>)value);}elseif(valueinstanceofManagedProperties){Propertiesoriginal=(Properties)value;Propertiescopy=newProperties();for(Map.Entry<Object,Object>propEntry:original.entrySet()){ObjectpropKey=propEntry.getKey();ObjectpropValue=propEntry.getValue();if(propKeyinstanceofTypedStringValue){propKey=evaluate((TypedStringValue)propKey);}if(propValueinstanceofTypedStringValue){propValue=evaluate((TypedStringValue)propValue);}copy.put(propKey,propValue);}returncopy;}elseif(valueinstanceofTypedStringValue){//Convertvaluetotargettypehere.TypedStringValuetypedStringValue=(TypedStringValue)value;ObjectvalueObject=evaluate(typedStringValue);try{Class<?>resolvedTargetType=resolveTargetType(typedStringValue);if(resolvedTargetType!=null){returnthis.typeConverter.convertIfNecessary(valueObject,resolvedTargetType);}else{returnvalueObject;}}catch(Throwableex){//Improvethemessagebyshowingthecontext.thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,“ErrorconvertingtypedStringvaluefor“+argName,ex);}}else{returnevaluate(value);}}| | :-----: |

这里主要关注两类解析,

RuntimeBeanReference 类型解析

对应需要被解析的配置为john的 propertyspouse,它所对应的值是另一个 beanjane;既是一个去解析一个ref bean

| 1|<propertyname=“spouse”ref=“jane”/>| | :-----: | | 1|<propertyname=“spouse”ref=“jane”/> |

所以可以看到,源码中是通过resolveReference方法调用AbstractBeanFactory#getBean方法去实例化一个beanjane并返回;对应的源码如下,
BeanDefinitionValueResolver#resolveReference

| 12345678910111213141516171819202122232425262728|/**Resolveareferencetoanotherbeaninthefactory./privateObjectresolveReference(ObjectargName,RuntimeBeanReferenceref){try{StringrefName=ref.getBeanName();refName=String.valueOf(doEvaluate(refName));if(ref.isToParent()){if(this.beanFactory.getParentBeanFactory()==null){thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,“Can’tresolvereferencetobean‘”+refName+“‘inparentfactory:noparentfactoryavailable”);}returnthis.beanFactory.getParentBeanFactory().getBean(refName);}else{Objectbean=this.beanFactory.getBean(refName);//去得到这个refbeanthis.beanFactory.registerDependentBean(refName,this.beanName);//注册returnbean;}}catch(BeansExceptionex){thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,“Cannotresolvereferencetobean‘”+ref.getBeanName()+“‘whilesetting“+argName,ex);}}| | :-----: | | 12345678910111213141516171819202122232425262728|/**Resolveareferencetoanotherbeaninthefactory./privateObjectresolveReference(ObjectargName,RuntimeBeanReferenceref){try{StringrefName=ref.getBeanName();refName=String.valueOf(doEvaluate(refName));if(ref.isToParent()){if(this.beanFactory.getParentBeanFactory()==null){thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,“Can’tresolvereferencetobean‘”+refName+“‘inparentfactory:noparentfactoryavailable”);}returnthis.beanFactory.getParentBeanFactory().getBean(refName);}else{Objectbean=this.beanFactory.getBean(refName);//去得到这个refbeanthis.beanFactory.registerDependentBean(refName,this.beanName);//注册returnbean;}}catch(BeansExceptionex){thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,“Cannotresolvereferencetobean‘”+ref.getBeanName()+“‘whilesetting“+argName,ex);}} |

通过调用this.beanFactory.getBean(refName)再次进入Do Get Bean 流程初始化得到该ref bean;

最后,将解析出来的 Property value 放在一个deepCopy的 ArrayList 列表对象中;顾名思义,就是对值进行了一次深度的拷贝,然后将其作为 bean 的参数,随后开始进行赋值操作);

TypedStringValue 类型解析

这里主要被解析的 Property value 的类型配置为

| 1|<propertyname=“name”value=“JohnDoe”/>| | :-----: | | 1|<propertyname=“name”value=“JohnDoe”/> |

其 Property value 的值在配置文件中就是一个纯的字符串类型;但从源码中可以知道,Property value 是可以包含 value type 的,所以,在解析 TypedStringValue 的时候,需要根据 value type 进行解析;具体逻辑参考resolveTargetType(typedStringValue);方法。

set property value to bean

此步骤的主流程主要是通过Java Method 反射解析出来的值赋值给当前的 bean;对应时序图中的Step 1.8 setPropertyValues

可以看到,通过遍历deepCopyArrayList 对象中已经解析过后的 PropertyValue,最终由BeanWrapperImpl对象通过方法的反射,将值注入给当前的 bean,Step 1.8.1.2.1.2.2 writeMethod.invoke

BeanWrapperImpl.java省略了大部分无关紧要的代码,

| 1234567891011121314151617181920212223242526|@OverridepublicvoidsetValue(finalObjectobject,ObjectvalueToApply)throwsException{finalMethodwriteMethod=(this.pdinstanceofGenericTypeAwarePropertyDescriptor?((GenericTypeAwarePropertyDescriptor)this.pd).getWriteMethodForActualAccess():this.pd.getWriteMethod());if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())&&!writeMethod.isAccessible()){if(System.getSecurityManager()!=null){AccessController.doPrivileged(newPrivilegedAction<Object>(){@OverridepublicObjectrun(){writeMethod.setAccessible(true);returnnull;}});}else{writeMethod.setAccessible(true);}}….writeMethod.invoke(getWrappedInstance(),valueToApply);….}| | :-----: | | 1234567891011121314151617181920212223242526|@OverridepublicvoidsetValue(finalObjectobject,ObjectvalueToApply)throwsException{finalMethodwriteMethod=(this.pdinstanceofGenericTypeAwarePropertyDescriptor?((GenericTypeAwarePropertyDescriptor)this.pd).getWriteMethodForActualAccess():this.pd.getWriteMethod());if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())&&!writeMethod.isAccessible()){if(System.getSecurityManager()!=null){AccessController.doPrivileged(newPrivilegedAction<Object>(){@OverridepublicObjectrun(){writeMethod.setAccessible(true);returnnull;}});}else{writeMethod.setAccessible(true);}}….writeMethod.invoke(getWrappedInstance(),valueToApply);….} |

通过这一步,将相关的 propertypopulate给 bean 以后,才算 bean 的实例化完成;

第三件事情:initialize bean

正如流程图中所描述的那样,这个步骤的名字非常然人迷惑,我将流程图中写的备注摘录如下,

“注意, 这里的名称很容易让人产生混淆, 很容易让人产生这样一个疑问, 前面不是已经初始化好了, bean 创建好了, bean 相关的 property 也设置好了, 怎么这里还要进行初始化? 这里其实恰恰充分体现了西方人写代码的严谨, 前面的部分叫做 instantiation, 叫做”实例化”, 而这里叫做 initialization, 叫做 “初始化”; 这样一说, 差不多就明白了, “实例化”就是从 class 得到 instance 的过程; 而”初始化”, 包含的意义更广泛, 其意义包含了”实例化”和其它对 instance 的修饰的过程, 而这里, 其实就是对已经创建好的 bean instance 进行”修饰”的过程。”

所以,这里的 initialize 其实就是对通过instantiate beanpopulate bean两个步骤实例化好的 bean 进行后续必要的修饰;我们通过流程图来看看,它是怎么去修饰的,
20191102100745\_5.pnginitialize-bean-process.png

通过AbstractAutowireCapableBeanFactory#initializeBean方法进行对 bean 的修饰过程,看源码,(删除了大部分不相关的代码)

AbstractAutowireCapableBeanFactory.java

| 123456789101112131415161718192021222324252627|protectedObjectinitializeBean(finalStringbeanName,finalObjectbean,RootBeanDefinitionmbd){invokeAwareMethods(beanName,bean);//调用实现了Aware接口的方法,比如注入ApplicationContext…ObjectwrappedBean=bean;if(mbd==null||!mbd.isSynthetic()){//调用bean-post-processor的beforeinitialization回调方法wrappedBean=applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);}try{invokeInitMethods(beanName,wrappedBean,mbd);//调用InitializingBean#afterPropertiesSet回调}catch(Throwableex){thrownewBeanCreationException((mbd!=null?mbd.getResourceDescription():null),beanName,“Invocationofinitmethodfailed”,ex);}if(mbd==null||!mbd.isSynthetic()){//调用bean-post-processor的afterinitialization回调方法wrappedBean=applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);}returnwrappedBean;//这里的wrappedbean指的是被bean-post-processor修饰以后的包装bean}| | :-----: | :-----: | :-----: | :-----: | :-----: | | 123456789101112131415161718192021222324252627|protectedObjectinitializeBean(finalStringbeanName,finalObjectbean,RootBeanDefinitionmbd){invokeAwareMethods(beanName,bean);//调用实现了Aware接口的方法,比如注入ApplicationContext…ObjectwrappedBean=bean;if(mbd==null | !mbd.isSynthetic()){//调用bean-post-processor的beforeinitialization回调方法wrappedBean=applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);}try{invokeInitMethods(beanName,wrappedBean,mbd);//调用InitializingBean#afterPropertiesSet回调}catch(Throwableex){thrownewBeanCreationException((mbd!=null?mbd.getResourceDescription():null),beanName,“Invocationofinitmethodfailed”,ex);}if(mbd==null | !mbd.isSynthetic()){//调用bean-post-processor的afterinitialization回调方法wrappedBean=applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);}returnwrappedBean;//这里的wrappedbean指的是被bean-post-processor修饰以后的包装bean} |

整个过程可以理解为三大块,

下面,我们依次来梳理这三个部分;

注入 Aware 对象

对应流程图中的Step 1.1 invokeAwareMethods,该步骤注册所有实现了Aware接口的 beans

Aware.java

| 123456789101112131415161718192021|/MarkersuperinterfaceindicatingthatabeaniseligibletobenotifiedbytheSpringcontainerofaparticularframeworkobjectthroughacallback-stylemethod.Actualmethodsignatureisdeterminedbyindividualsubinterfaces,butshouldtypicallyconsistofjustonevoid-returningmethodthatacceptsasingleargument.<p>Notethatmerelyimplementing{@linkAware}providesnodefaultfunctionality.Rather,processingmustbedoneexplicitly,forexampleina{@linkorg.springframework.beans.factory.config.BeanPostProcessorBeanPostProcessor}.Referto{@linkorg.springframework.context.support.ApplicationContextAwareProcessor}and{@linkorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}forexamplesofprocessing{@codeAware}interfacecallbacks.@authorChrisBeams@since3.1/publicinterfaceAware{}| | :-----: | | 123456789101112131415161718192021|/MarkersuperinterfaceindicatingthatabeaniseligibletobenotifiedbytheSpringcontainerofaparticularframeworkobjectthroughacallback-stylemethod.Actualmethodsignatureisdeterminedbyindividualsubinterfaces,butshouldtypicallyconsistofjustonevoid-returningmethodthatacceptsasingleargument.<p>Notethatmerelyimplementing{@linkAware}providesnodefaultfunctionality.Rather,processingmustbedoneexplicitly,forexampleina{@linkorg.springframework.beans.factory.config.BeanPostProcessorBeanPostProcessor}.Referto{@linkorg.springframework.context.support.ApplicationContextAwareProcessor}and{@linkorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}forexamplesofprocessing{@codeAware}interfacecallbacks.@authorChrisBeams@since3.1/publicinterfaceAware{} |

从 Aware 接口的注释中可以看到,允许实现了该 Aware 接口的当前 bean 能够有机会通过回调的方式注入 Spring 容器中默认实现了 Aware 接口的 bean,比如 BeanFactory 等;看看源码,

AbstractAutowireCapableBeanFactory.java

| 12345678910111213|privatevoidinvokeAwareMethods(finalStringbeanName,finalObjectbean){if(beaninstanceofAware){if(beaninstanceofBeanNameAware){((BeanNameAware)bean).setBeanName(beanName);}if(beaninstanceofBeanClassLoaderAware){((BeanClassLoaderAware)bean).setBeanClassLoader(getBeanClassLoader());}if(beaninstanceofBeanFactoryAware){((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}}| | :-----: | | 12345678910111213|privatevoidinvokeAwareMethods(finalStringbeanName,finalObjectbean){if(beaninstanceofAware){if(beaninstanceofBeanNameAware){((BeanNameAware)bean).setBeanName(beanName);}if(beaninstanceofBeanClassLoaderAware){((BeanClassLoaderAware)bean).setBeanClassLoader(getBeanClassLoader());}if(beaninstanceofBeanFactoryAware){((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}} |

可以看到,注入了三种情况,

  1. 当当前 bean 实现了 BeanNameAware 接口,只是调用了 setBeanName;给我目前的感觉是,没有起到什么大的作用,把自己的 beanName 设置给自己,有什么用处?嗯,倒是想到一个,logging;
  2. 当当前 bean 实现了 BeanClassLoaderAware 接口,将 Spring 容器的 BeanClassLoader 注入到当前 bean;记住,如果想要获得加载 Bean 当前的 ClassLoader 对象的时候,只需要让 Bean 实现 BeanClassLoaderAware 接口并实现相应接口方法即可。
  3. 当当前 bean 实现了 BeanFactoryAware 接口,将 Spring 容器中与 bean 初始化相关的 BeanFactory 实例(这里对应的是 DefaultListableBeanFactory 实例)注册给当前的 bean。

当梳理完这个部分以后,我相信读者会和我一样有这样的疑问,我们不是经常通过Aware的方式注入ApplicaitonContext对象的吗?但和明显,上述的代码并没有注入ApplicationContext对象呀?看如下部分分析,

下列部分是延生部分

但是要特别特别注意的是,这里并没有注入ApplicationContext对象,要注入ApplicaitonContext对象,bean 必须实现ApplicatonContextAware接口;

ApplicationContextAware.java

| 123456789101112131415161718|publicinterfaceApplicationContextAwareextendsAware{/**SettheApplicationContextthatthisobjectrunsin.Normallythiscallwillbeusedtoinitializetheobject.<p>Invokedafterpopulationofnormalbeanpropertiesbutbeforeaninitcallbacksuchas{@linkorg.springframework.beans.factory.InitializingBean#afterPropertiesSet()}oracustominit-method.Invokedafter{@linkResourceLoaderAware#setResourceLoader},{@linkApplicationEventPublisherAware#setApplicationEventPublisher}and{@linkMessageSourceAware},ifapplicable.@paramapplicationContexttheApplicationContextobjecttobeusedbythisobject@throwsApplicationContextExceptionincaseofcontextinitializationerrors@throwsBeansExceptionifthrownbyapplicationcontextmethods@seeorg.springframework.beans.factory.BeanInitializationException/voidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException;}| | :-----: | | 123456789101112131415161718|publicinterfaceApplicationContextAwareextendsAware{/**SettheApplicationContextthatthisobjectrunsin.Normallythiscallwillbeusedtoinitializetheobject.<p>Invokedafterpopulationofnormalbeanpropertiesbutbeforeaninitcallbacksuchas{@linkorg.springframework.beans.factory.InitializingBean#afterPropertiesSet()}oracustominit-method.Invokedafter{@linkResourceLoaderAware#setResourceLoader},{@linkApplicationEventPublisherAware#setApplicationEventPublisher}and{@linkMessageSourceAware},ifapplicable.@paramapplicationContexttheApplicationContextobjecttobeusedbythisobject@throwsApplicationContextExceptionincaseofcontextinitializationerrors@throwsBeansExceptionifthrownbyapplicationcontextmethods@seeorg.springframework.beans.factory.BeanInitializationException/voidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException;} |

从注解中可以看到,它明确标注,是在populate bean以后,在处理 InitializingBean 接口回调之前调用,那是到底是在什么时刻呢?我们查看下方法setApplicationContext方法在 workspace 中的引用,它是在ApplicationContextAwareProcessor#invokeAwareInterfaces方法中被调用,而ApplicationContextAwareProcessor正好是一个BeanPostProcessor对象,所以,ApplicaitonContext对象实际上是在bean-post-procesor before initialization流程中被注入的,看源码,

ApplicationContextAwareProcessor.java(省略了大部分不相关的代码)

| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657|classApplicationContextAwareProcessorimplementsBeanPostProcessor{privatefinalConfigurableApplicationContextapplicationContext;privatefinalStringValueResolverembeddedValueResolver;/**CreateanewApplicationContextAwareProcessorforthegivencontext./publicApplicationContextAwareProcessor(ConfigurableApplicationContextapplicationContext){this.applicationContext=applicationContext;this.embeddedValueResolver=newEmbeddedValueResolver(applicationContext.getBeanFactory());}@OverridepublicObjectpostProcessBeforeInitialization(finalObjectbean,StringbeanName)throwsBeansException{AccessControlContextacc=null;….invokeAwareInterfaces(bean);….returnbean;}privatevoidinvokeAwareInterfaces(Objectbean){if(beaninstanceofAware){if(beaninstanceofEnvironmentAware){((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());}if(beaninstanceofEmbeddedValueResolverAware){((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if(beaninstanceofResourceLoaderAware){((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);}if(beaninstanceofApplicationEventPublisherAware){((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);}if(beaninstanceofMessageSourceAware){((MessageSourceAware)bean).setMessageSource(this.applicationContext);}if(beaninstanceofApplicationContextAware){((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);}}}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){returnbean;}}| | :-----: | | 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657|classApplicationContextAwareProcessorimplementsBeanPostProcessor{privatefinalConfigurableApplicationContextapplicationContext;privatefinalStringValueResolverembeddedValueResolver;/**CreateanewApplicationContextAwareProcessorforthegivencontext./publicApplicationContextAwareProcessor(ConfigurableApplicationContextapplicationContext){this.applicationContext=applicationContext;this.embeddedValueResolver=newEmbeddedValueResolver(applicationContext.getBeanFactory());}@OverridepublicObjectpostProcessBeforeInitialization(finalObjectbean,StringbeanName)throwsBeansException{AccessControlContextacc=null;….invokeAwareInterfaces(bean);….returnbean;}privatevoidinvokeAwareInterfaces(Objectbean){if(beaninstanceofAware){if(beaninstanceofEnvironmentAware){((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());}if(beaninstanceofEmbeddedValueResolverAware){((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if(beaninstanceofResourceLoaderAware){((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);}if(beaninstanceofApplicationEventPublisherAware){((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);}if(beaninstanceofMessageSourceAware){((MessageSourceAware)bean).setMessageSource(this.applicationContext);}if(beaninstanceofApplicationContextAware){((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);}}}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){returnbean;}} |

回调 bean-post-processors 接口方法

先来看看BeanPostProcessor接口的源码,

| 123456789101112131415161718192021222324252627282930313233343536373839|publicinterfaceBeanPostProcessor{/ApplythisBeanPostProcessortothegivennewbeaninstance<i>before</i>anybeaninitializationcallbacks(likeInitializingBean’s{@codeafterPropertiesSet}oracustominit-method).Thebeanwillalreadybepopulatedwithpropertyvalues.Thereturnedbeaninstancemaybeawrapperaroundtheoriginal.@parambeanthenewbeaninstance@parambeanNamethenameofthebean@returnthebeaninstancetouse,eithertheoriginalorawrappedone;if{@codenull},nosubsequentBeanPostProcessorswillbeinvoked@throwsorg.springframework.beans.BeansExceptionincaseoferrors@seeorg.springframework.beans.factory.InitializingBean#afterPropertiesSet/ObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException;/ApplythisBeanPostProcessortothegivennewbeaninstance<i>after</i>anybeaninitializationcallbacks(likeInitializingBean’s{@codeafterPropertiesSet}oracustominit-method).Thebeanwillalreadybepopulatedwithpropertyvalues.Thereturnedbeaninstancemaybeawrapperaroundtheoriginal.<p>IncaseofaFactoryBean,thiscallbackwillbeinvokedforboththeFactoryBeaninstanceandtheobjectscreatedbytheFactoryBean(asofSpring2.0).Thepost-processorcandecidewhethertoapplytoeithertheFactoryBeanorcreatedobjectsorboththroughcorresponding{@codebeaninstanceofFactoryBean}checks.<p>Thiscallbackwillalsobeinvokedafterashort-circuitingtriggeredbya{@linkInstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}method,incontrasttoallotherBeanPostProcessorcallbacks.@parambeanthenewbeaninstance@parambeanNamethenameofthebean@returnthebeaninstancetouse,eithertheoriginalorawrappedone;if{@codenull},nosubsequentBeanPostProcessorswillbeinvoked@throwsorg.springframework.beans.BeansExceptionincaseoferrors@seeorg.springframework.beans.factory.InitializingBean#afterPropertiesSet@seeorg.springframework.beans.factory.FactoryBean/ObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException;}| | :-----: | | 123456789101112131415161718192021222324252627282930313233343536373839|publicinterfaceBeanPostProcessor{/ApplythisBeanPostProcessortothegivennewbeaninstance<i>before</i>anybeaninitializationcallbacks(likeInitializingBean’s{@codeafterPropertiesSet}oracustominit-method).Thebeanwillalreadybepopulatedwithpropertyvalues.Thereturnedbeaninstancemaybeawrapperaroundtheoriginal.@parambeanthenewbeaninstance@parambeanNamethenameofthebean@returnthebeaninstancetouse,eithertheoriginalorawrappedone;if{@codenull},nosubsequentBeanPostProcessorswillbeinvoked@throwsorg.springframework.beans.BeansExceptionincaseoferrors@seeorg.springframework.beans.factory.InitializingBean#afterPropertiesSet/ObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException;/ApplythisBeanPostProcessortothegivennewbeaninstance<i>after</i>anybeaninitializationcallbacks(likeInitializingBean’s{@codeafterPropertiesSet}oracustominit-method).Thebeanwillalreadybepopulatedwithpropertyvalues.Thereturnedbeaninstancemaybeawrapperaroundtheoriginal.<p>IncaseofaFactoryBean,thiscallbackwillbeinvokedforboththeFactoryBeaninstanceandtheobjectscreatedbytheFactoryBean(asofSpring2.0).Thepost-processorcandecidewhethertoapplytoeithertheFactoryBeanorcreatedobjectsorboththroughcorresponding{@codebeaninstanceofFactoryBean}checks.<p>Thiscallbackwillalsobeinvokedafterashort-circuitingtriggeredbya{@linkInstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}method,incontrasttoallotherBeanPostProcessorcallbacks.@parambeanthenewbeaninstance@parambeanNamethenameofthebean@returnthebeaninstancetouse,eithertheoriginalorawrappedone;if{@codenull},nosubsequentBeanPostProcessorswillbeinvoked@throwsorg.springframework.beans.BeansExceptionincaseoferrors@seeorg.springframework.beans.factory.InitializingBean#afterPropertiesSet@seeorg.springframework.beans.factory.FactoryBean/ObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException;} |

该接口定义了两个回调方法,

  • Object postProcessBeforeInitialization(Object bean, String beanName)
    从方法的注释中不难发现,该方法是在回调 InitializeBean 接口方法之前调用,并且是在populate bean) 之后进行的调用,通常是对原有 bean 做一层封装,然后返回该封装对象;这就是我在前文所描述的,其实就是是对原有 bean 起到修饰的作用;
  • Object postProcessAfterInitialization(Object bean, String beanName)
    从方法的注释中不难发现,该方法是在回调 InitializeBean 接口方法之前调用,同样也是在populate bean) 之后进行的调用

所以,bean-post-processors 总共有两次调用的时机,分别是before initializationafter initialization,而且要特别注意的是,该回调方法是针对对容器中所有的普通 bean 进行的回调;

before initialization

该步骤对应Step 1.2 applyBeanPostProcessorsBeforeInitialization,然后正式调用Step 1.2.1 beanPostProcessor.postProcessBeforeInitializationbean-post-processor 的回调方法,不过这里要注意的是,如果Step 1.2.1返回 null,会终止余下的 post-bean-processor 的执行,并且直接返回一个 null,该 null 同样被视为是封装后的产物,既然是 null,那么后续的 bean-post-processor 也无需处理了,也无法对原有的 bean 进行包装了.. 不过,我到觉得这里的Spring 源码的逻辑应该改进一下,不允许返回 null 的情况,如果返回 null 则报错最好,因为 bean-post-processor 是对原有 bean 进行修饰,是新增属性,而非干掉实例本身.. 来看看源码,

AbstractAutowireCapableBeanFactory.java

| 12345678910111213|@OverridepublicObjectapplyBeanPostProcessorsBeforeInitialization(ObjectexistingBean,StringbeanName)throwsBeansException{Objectresult=existingBean;for(BeanPostProcessorbeanProcessor:getBeanPostProcessors()){result=beanProcessor.postProcessBeforeInitialization(result,beanName);if(result==null){returnresult;}}returnresult;}| | :-----: | | 12345678910111213|@OverridepublicObjectapplyBeanPostProcessorsBeforeInitialization(ObjectexistingBean,StringbeanName)throwsBeansException{Objectresult=existingBean;for(BeanPostProcessorbeanProcessor:getBeanPostProcessors()){result=beanProcessor.postProcessBeforeInitialization(result,beanName);if(result==null){returnresult;}}returnresult;} |

如果某个 beanProcessor 处理返回一个 null 则直接返回,并且终止其余的 bean-post-processors

after initialization

对应的是step 1.4 applyBeanPostProcessorsAfterInitialization步骤,里面的逻辑和before initialization逻辑类似,不再赘述。

回调 InitializingBean 接口方法

该步骤对应的是Step 1.3: invokeInitMethod,回调 InitializingBean 接口方法,看源码,

AbstractAutowireCapableBeanFactory.java(删除了大部分不相关的代码)

| 123456789101112131415161718192021|protectedvoidinvokeInitMethods(StringbeanName,finalObjectbean,RootBeanDefinitionmbd)throwsThrowable{booleanisInitializingBean=(beaninstanceofInitializingBean);if(isInitializingBean&&(mbd==null||!mbd.isExternallyManagedInitMethod(“afterPropertiesSet”))){if(logger.isDebugEnabled()){logger.debug(“InvokingafterPropertiesSet()onbeanwithname‘”+beanName+“‘”);}…..((InitializingBean)bean).afterPropertiesSet();…..}if(mbd!=null){StringinitMethodName=mbd.getInitMethodName();if(initMethodName!=null&&!(isInitializingBean&&“afterPropertiesSet”.equals(initMethodName))&&!mbd.isExternallyManagedInitMethod(initMethodName)){invokeCustomInitMethod(beanName,bean,mbd);}}}| | :-----: | :-----: | :-----: | | 123456789101112131415161718192021|protectedvoidinvokeInitMethods(StringbeanName,finalObjectbean,RootBeanDefinitionmbd)throwsThrowable{booleanisInitializingBean=(beaninstanceofInitializingBean);if(isInitializingBean&&(mbd==null | !mbd.isExternallyManagedInitMethod(“afterPropertiesSet”))){if(logger.isDebugEnabled()){logger.debug(“InvokingafterPropertiesSet()onbeanwithname‘”+beanName+“‘”);}…..((InitializingBean)bean).afterPropertiesSet();…..}if(mbd!=null){StringinitMethodName=mbd.getInitMethodName();if(initMethodName!=null&&!(isInitializingBean&&“afterPropertiesSet”.equals(initMethodName))&&!mbd.isExternallyManagedInitMethod(initMethodName)){invokeCustomInitMethod(beanName,bean,mbd);}}} |

可以看到,主要回调的是InitializingBean接口的afterPropertiesSet方法,所以,我们可以让某个 bean 实现 InitializingBean 接口,并通过该接口实现一些当 bean 实例化好以后的回调方法,注意afterPropertiesSet并不返回任何值,所以,这里不是像 bean-post-processor 那样对 bean 起到修饰的作用,而是起到纯粹的调用作用;

总结(我的思考)

以上便是 Spring IoC 容器的核心实现了,容器要达到的最本质的目的就是IoC反转控制,由容器来负责管理对象实例相关依赖的初始化和注入,而不再是由 bean 自己去控制自己的依赖的初始化和注入过程了;而IoC的实现是通过DI既是依赖注入实现的;也就是为什么上面所介绍的内容都是围绕着 Spring 容器如何实例化一个 bean,如何赋值,如何进行回调等一系列在 bean 的构建声明周期过程中的种种行为;

这样做能达到的好处就是,

  1. 实现了对象的依赖属性和依赖对象的高度可定制化,我们可以通过容器配置的方式,轻松的修改 bean 所的依赖对象,以改变原有的其行为;

    (这里我突然想到“微内核架构”,Java 的一种内置的依赖注入的方式,通过在 META-INF 中配置接口属性文件,里面其实就是配置的一个接口的实现类,通过它来控制接口在 JVM 中该接口所使用的实现类;但它只是控制某个接口如何在 JVM 中实现,将接口的实现翻转控制了,而 Spring 是对所有的 Class Instance 进行翻转控制,所以一个是站在局部上的反转控制设计,一个是站在全局上的反转控制设计,不可同日而语!)

  2. 通过bean-post-processor 扩展点能够对原始的 bean 进行包装,通过这样的方式,我们可以包装得到一个 proxy bean,提供相关的 AOP 操作,比如提供事务,异常处理等等方法注入的实现;


来源:http://ddrv.cn

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Spring Core Container 源码分析三:Spring Beans 初始化流程分析

相关推荐