上一章,我们从后置处理器的初始化开始,了解了 bean 在实例化前的一些处理,以及实例化过程中的一些逻辑。bean 对象实例化出来之后,下一步就要给 bean 的属性赋值,以及组件的依赖注入了。
本章主要会涉及到的原理部分:
重要的 BeanPostProcessor
功能解析
1. doCreateBean
上一章中我们只解析了 doCreateBean
方法中的第一小段,接下来我们继续往下读。
1.1 回调MergedBeanDefinitionPostProcessor
复制 // ......
// Allow post-processors to modify the merged bean definition.
synchronized ( mbd . postProcessingLock ) {
if ( ! mbd . postProcessed ) {
try {
applyMergedBeanDefinitionPostProcessors(mbd , beanType , beanName) ;
}
// catch ......
mbd . postProcessed = true ;
}
}
// ......
这个阶段它会回调所有的 MergedBeanDefinitionPostProcessor
,这个阶段本身没什么好解释的,不过这里面有几个关键的 MergedBeanDefinitionPostProcessor
实现,咱在这里还是有必要展开讲一下的。
1.1.1 InitDestroyAnnotationBeanPostProcessor
顾名思义,它是处理初始化和销毁注解的后置处理器,它的核心处理逻辑如下:
复制 public void postProcessMergedBeanDefinition( RootBeanDefinition beanDefinition , Class<?> beanType , String beanName) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType) ;
metadata . checkConfigMembers (beanDefinition);
}
很明显,findLifecycleMetadata
方法是查找 bean 的生命周期元信息,进入到该方法中:
复制 private LifecycleMetadata findLifecycleMetadata( Class<?> clazz) {
if ( this . lifecycleMetadataCache == null ) {
// Happens after deserialization, during destruction...
return buildLifecycleMetadata(clazz) ;
}
// 构建缓存 ......
return metadata;
}
这里又是用缓存机制,把 bean 的初始化和销毁注解信息都保存到 lifecycleMetadataCache
里了。咱主要关注的是 buildLifecycleMetadata
方法,看它都是怎么搞的。
复制 private LifecycleMetadata buildLifecycleMetadata( final Class<?> clazz) {
if ( ! AnnotationUtils . isCandidateClass (clazz , Arrays . asList ( this . initAnnotationType , this . destroyAnnotationType ))) {
return this . emptyLifecycleMetadata ;
}
List < LifecycleElement > initMethods = new ArrayList <>();
List < LifecycleElement > destroyMethods = new ArrayList <>();
Class < ? > targetClass = clazz;
do {
final List < LifecycleElement > currInitMethods = new ArrayList <>();
final List < LifecycleElement > currDestroyMethods = new ArrayList <>();
// 反射所有的public方法
ReflectionUtils . doWithLocalMethods (targetClass , method -> {
// 寻找所有被初始化注解标注的方法
if ( this . initAnnotationType != null && method . isAnnotationPresent ( this . initAnnotationType )) {
LifecycleElement element = new LifecycleElement(method) ;
currInitMethods . add (element);
}
// 寻找所有被销毁注解标注的方法
if ( this . destroyAnnotationType != null && method . isAnnotationPresent ( this . destroyAnnotationType )) {
currDestroyMethods . add ( new LifecycleElement(method) );
}
});
initMethods . addAll ( 0 , currInitMethods);
destroyMethods . addAll (currDestroyMethods);
targetClass = targetClass . getSuperclass ();
} // 依次向上寻找父类
while (targetClass != null && targetClass != Object . class );
return ( initMethods . isEmpty () && destroyMethods . isEmpty () ? this . emptyLifecycleMetadata :
new LifecycleMetadata(clazz , initMethods , destroyMethods) );
}
这段源码还是比较容易理解的,它会寻找这个 bean 所属的 Class
中是否有包含初始化注解和销毁注解的方法。而初始化注解、销毁注解分别是啥呢?在子类 CommonAnnotationBeanPostProcessor
中有指定:
复制 setInitAnnotationType( PostConstruct . class ) ;
setDestroyAnnotationType( PreDestroy . class ) ;
好吧,果然还是 JSR 250 的那一套。那合着说,**InitDestroyAnnotationBeanPostProcessor**
就是收集标注了 **@PostConstruct**
和 **@PreDestroy**
注解的后置处理器 呗。
1.1.2 CommonAnnotationBeanPostProcessor
呦,马上就到这个子类了,咱看看这个类里有什么扩展:
复制 public void postProcessMergedBeanDefinition( RootBeanDefinition beanDefinition , Class<?> beanType , String beanName) {
// 调用InitDestroyAnnotationBeanPostProcessor
super . postProcessMergedBeanDefinition (beanDefinition , beanType , beanName);
// 收集注入相关的信息
InjectionMetadata metadata = findResourceMetadata(beanName , beanType , null ) ;
metadata . checkConfigMembers (beanDefinition);
}
除了调用父类 InitDestroyAnnotationBeanPostProcessor
的收集动作之外,它在这里还要收集有关注入的注解信息。与上面的 findLifecycleMetadata
方法类似,它也是设置有缓存的机制,我们直接看实际干活的方法了:
复制 do {
final List < InjectionMetadata . InjectedElement > currElements = new ArrayList <>();
ReflectionUtils . doWithLocalFields (targetClass , field -> {
if (webServiceRefClass != null && field . isAnnotationPresent (webServiceRefClass)) {
if ( Modifier . isStatic ( field . getModifiers ())) {
throw new IllegalStateException( "@WebServiceRef annotation is not supported on static fields" ) ;
}
currElements . add ( new WebServiceRefElement(field , field , null ) );
}
else if (ejbClass != null && field . isAnnotationPresent (ejbClass)) {
if ( Modifier . isStatic ( field . getModifiers ())) {
throw new IllegalStateException( "@EJB annotation is not supported on static fields" ) ;
}
currElements . add ( new EjbRefElement(field , field , null ) );
}
else if ( field . isAnnotationPresent ( Resource . class )) {
if ( Modifier . isStatic ( field . getModifiers ())) {
throw new IllegalStateException( "@Resource annotation is not supported on static fields" ) ;
}
if ( ! this . ignoredResourceTypes . contains ( field . getType () . getName ())) {
currElements . add ( new ResourceElement(field , field , null ) );
}
}
});
由这段节选的源码可见,它还能支持 JAVA EE 规范中的 @WebServiceRef
、@EJB
、@Resource
注解,并封装对应的注解信息。由于我们已经对 EJB 等家伙不关注了,所以这里小伙伴们只需要知道它相当于额外收集了 @Resource
注解的信息即可。
1.1.3 AutowiredAnnotationBeanPostProcessor
有了前面两个后置处理器的知识,这个后置处理器的功能不用看也就能猜得到了吧:它应该是收集自动注入的注解信息 的。底层的原理与前两者的逻辑设计一模一样,小册就不重复贴出了,这里重点说一下它支持的注解。
复制 public AutowiredAnnotationBeanPostProcessor() {
this . autowiredAnnotationTypes . add ( Autowired . class );
this . autowiredAnnotationTypes . add ( Value . class );
try {
this . autowiredAnnotationTypes . add (( Class<? extends Annotation > )
ClassUtils . forName ( "javax.inject.Inject" , AutowiredAnnotationBeanPostProcessor . class . getClassLoader ()));
}
}
可以发现,AutowiredAnnotationBeanPostProcessor
在构造方法中,就已经指定好它默认支持 @Autowired
注解、@Value
注解,如果 classpath 下有来自 JSR 330 的 @Inject
注解,也会一并支持。
1.1.4 注解后置处理器小结
从这几个后置处理器中,我们就可以发现,可以支持 bean 中标注的注解的后置处理器,它们的处理方式都是先收集注解标注的信息,保存到缓存中,随后再处理时,只需要从缓存中取就可以 了。
1.2 早期bean对象引用的获取与缓存
复制 // ......
boolean earlySingletonExposure = ( mbd . isSingleton () && this . allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName) );
if (earlySingletonExposure) {
// logger ......
// 处理循环依赖的问题
addSingletonFactory(beanName , () -> getEarlyBeanReference(beanName , mbd , bean)) ;
}
// ......
这里有一个获取早期 bean 对象引用的动作,这一步是为了解决 bean 之间的循环依赖问题。这里我们只是说一下这个早期 bean 对象的引用是个什么东西。
从前面的逻辑中,bean 被实例化出来之后还没有进行属性赋值和组件的依赖注入 ,但此时的 bean 对象已经实实在在的存在了 。如果在此期间,有另外的 bean 又需要创建它时,就不应该再创建同样的一个 bean 对象,而是直接拿到该引用 即可,这个设计就是为了解决 bean 之间的循环依赖而用(从 getEarlyBeanReference
方法的 javadoc 上也能看到)。
有关 bean 的循环依赖,在本小册中不会有涉及,在我的 《SpringBoot 小册》第 15 章 有完整的讲过 SpringFramework 解决循环依赖的全流程,有需要的小伙伴们可以跳转过去学习哦。
1.3 populateBean - 属性赋值+依赖注入
接下来的两步是挨着的:
复制 // ......
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName , mbd , instanceWrapper) ;
exposedObject = initializeBean(beanName , exposedObject , mbd) ;
}
// ......
这里我们先看 populateBean
这一步,由于这个方法中的内容还是比较多,我们拆解开来看。
1.3.1 检查bean&准备
复制 protected void populateBean( String beanName , RootBeanDefinition mbd , @ Nullable BeanWrapper bw) {
if (bw == null ) {
if ( mbd . hasPropertyValues ()) {
throw new BeanCreationException(
mbd . getResourceDescription() , beanName , "Cannot apply property values to null instance" ) ;
}
else {
// Skip property population phase for null instance.
return ;
}
}
// ......
这个地方仅仅是为了检查 BeanWrapper
中是否存在而已,没什么好说的。
1.3.2 回调InstantiationAwareBeanPostProcessor
复制 // ......
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if ( ! mbd . isSynthetic () && hasInstantiationAwareBeanPostProcessors() ) {
for ( BeanPostProcessor bp : getBeanPostProcessors() ) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if ( ! ibp . postProcessAfterInstantiation ( bw . getWrappedInstance () , beanName)) {
return ;
}
}
}
}
// ......
这个部分很明显就是回调所有的 InstantiationAwareBeanPostProcessor
而已,不过这上面有好长一段注释,我们来看看它讲了些啥:
Give any InstantiationAwareBeanPostProcessors the opportunity to modify the state of the bean before properties are set. This can be used, for example, to support styles of field injection.
在设置属性之前,让任何 InstantiationAwareBeanPostProcessor
都有机会修改 bean 的状态,例如支持属性字段的注入。
哦,合着 postProcessAfterInstantiation
方法也是干预 bean 的属性等东西的呀。而且有一个小细节注意一下,postProcessAfterInstantiation
方法返回的是 boolean 类型,当 postProcessAfterInstantiation
返回 false 时,会直接 return 出去,不再执行下面的属性赋值 + 组件依赖注入的逻辑 !(通常这个方法一定是返回 true 的,底层默认也是返回 true )
可能会有小伙伴产生疑惑,那这个回调有什么可以利用的吗?注意思考,当 bean 的创建来到这个位置的时候,此时 bean 的状态如何?还是所有属性都为空吧,而且还都没有执行任何初始化的逻辑吧。所以这个回调的位置,就是让咱在 bean 已经初始化好,但还没有开始属性赋值和依赖注入时切入自定义逻辑 。
1.3.3 自动注入支持
复制 // ......
PropertyValues pvs = ( mbd . hasPropertyValues () ? mbd . getPropertyValues () : null );
// 解析出当前bean支持的自动注入模式
int resolvedAutowireMode = mbd . getResolvedAutowireMode ();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs) ;
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName , mbd , bw , newPvs) ;
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName , mbd , bw , newPvs) ;
}
pvs = newPvs;
}
// ......
这一部分的逻辑是支撑 “自动注入模式” 功能的,我们在第 24 章已经简单的讲过了,这里我们简单地看一下源码的实现就好了。
在上面先把当前正在创建的 bean 的自动注入模式解析出来,之后根据自动注入模式,执行对应的逻辑。这里我们以 byName
为例看一下它里面的实现。
复制 protected void autowireByName(
String beanName , AbstractBeanDefinition mbd , BeanWrapper bw , MutablePropertyValues pvs) {
String [] propertyNames = unsatisfiedNonSimpleProperties(mbd , bw) ;
for ( String propertyName : propertyNames) {
// 存在bean,就获取出来,添加依赖关系
if ( containsBean(propertyName) ) {
Object bean = getBean(propertyName) ;
pvs . add (propertyName , bean);
registerDependentBean(propertyName , beanName) ;
}
}
}
可以发现,这个逻辑是相当的简单吧!就仅仅是查出来,添加上依赖关系,就完事了 ,没有任何的多余动作,这部分的逻辑也没什么好说的咯。
另外留意一点!在这段代码执行完毕后,有 pvs = newPvs;
的步骤,它将这个过程中需要组件依赖注入的信息也都封装进了 PropertyValues
中了,所以此时 **pvs**
中就应该有一开始封装的信息,以及通过自动注入封装好的依赖信息 。
1.3.4 又回调InstantiationAwareBeanPostProcessor
复制 // ......
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors() ;
boolean needsDepCheck = ( mbd . getDependencyCheck () != AbstractBeanDefinition . DEPENDENCY_CHECK_NONE );
PropertyDescriptor [] filteredPds = null ;
if (hasInstAwareBpps) {
if (pvs == null ) {
pvs = mbd . getPropertyValues ();
}
for ( BeanPostProcessor bp : getBeanPostProcessors() ) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 【核心】回调postProcessProperties
PropertyValues pvsToUse = ibp . postProcessProperties (pvs , bw . getWrappedInstance () , beanName);
if (pvsToUse == null ) {
if (filteredPds == null ) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw , mbd . allowCaching ) ;
}
pvsToUse = ibp . postProcessPropertyValues (pvs , filteredPds , bw . getWrappedInstance () , beanName);
if (pvsToUse == null ) {
return ;
}
}
pvs = pvsToUse;
}
}
}
// ......
这一段源码又在取那些 InstantiationAwareBeanPostProcessor
了,不过注意这次回调的方法是 **postProcessProperties**
和 postProcessPropertyValues
方法了( postProcessPropertyValues
方法在 SpringFramework 5.1 之后被废弃了)。注意 postProcessProperties
方法会传入 PropertyValues
,也会返回 PropertyValues
,所以这个过程相当于反复给 **PropertyValues**
封装数据 。那这个封装的过程我们是有必要了解一下的。
之前在第 27 章我们已经知道,这个时机的回调是属性赋值和组件依赖注入的核心时机,所以我们需要关注这里面一个非常重要的后置处理器:**AutowiredAnnotationBeanPostProcessor**
。
AutowiredAnnotationBeanPostProcessor#postProcessProperties
AutowiredAnnotationBeanPostProcessor
的 postProcessProperties
方法的实现,看上去还蛮简单的:
复制 public PropertyValues postProcessProperties( PropertyValues pvs , Object bean , String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName , bean . getClass() , pvs) ;
try {
metadata . inject (bean , beanName , pvs);
} // catch ......
return pvs;
}
嗯,看到 findAutowiringMetadata
方法,是不是又想到了前面那个一模一样的套路呢?又是收集所有标注了 @Autowired
、@Value
、@Inject
注解的信息,返回回来。不过这里不只是收集了,它要真正的给 bean 对象的属性赋值 !
到这里,小伙伴是否有回想起在第 30 章中,我们说过的,在 BeanFactoryPostProcessor
或者 BeanDefinitionRegistryPostProcessor
中无法直接使用 @Autowired
直接注入 SpringFramework 中的内部组件(如 Environment
)?现在是否明白这个问题的答案了吗?当 **BeanDefinitionRegistryPostProcessor**
在初始化的阶段,还不存在 **BeanPostProcessor**
呢,所以那些用于支持依赖注入的后置处理器( **AutowiredAnnotationBeanPostProcessor**
)还没有被初始化,自然也就没办法支持注入了。正确的做法是借助 **Aware**
接口的回调注入。
metadata.inject
复制 public void inject( Object target , @ Nullable String beanName , @ Nullable PropertyValues pvs) throws Throwable {
Collection < InjectedElement > checkedElements = this . checkedElements ;
// 收集所有要注入的信息
Collection < InjectedElement > elementsToIterate =
(checkedElements != null ? checkedElements : this . injectedElements );
if ( ! elementsToIterate . isEmpty ()) {
// 迭代,依次注入
for ( InjectedElement element : elementsToIterate) {
// logger ......
element . inject (target , beanName , pvs);
}
}
}
整体逻辑还是非常简单的哈,给一个 bean 进行注入,就相当于给这个 bean 中需要注入的元素依次注入。
继续往下进入到 element.inject
方法,这里面就比较复杂了(因为它有两个重写的复杂方法),我们只需要看一下它的核心工作机制就好了:
复制 protected void inject( Object target , @ Nullable String requestingBeanName , @ Nullable PropertyValues pvs)
throws Throwable {
if ( this . isField ) {
// 反射注入字段
Field field = (Field) this . member ;
ReflectionUtils . makeAccessible (field);
field . set (target , getResourceToInject(target , requestingBeanName) );
}
else {
if ( checkPropertySkipping(pvs) ) {
return ;
}
try {
// 反射调用setter方法
Method method = (Method) this . member ;
ReflectionUtils . makeAccessible (method);
method . invoke (target , getResourceToInject(target , requestingBeanName) );
} // catch ......
}
}
嚯,这也太简单了吧,就仅仅是反射注入 / 调用呗?当然啦,太复杂的是这个方法重写的两个子类 AutowiredFieldElement
和 AutowiredMethodElement
,但它们处理的逻辑大同小异,只是处理步骤复杂了好多而已。小伙伴们没有必要深追这里面的实现细节,能对这个步骤的底层基本实现心领神会即可。
1.3.5 属性赋值
到这里为止,PropertyValues
的内容都封装好了,来看最后一段源码:
复制 // ......
if (needsDepCheck) {
if (filteredPds == null ) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw , mbd . allowCaching ) ;
}
checkDependencies(beanName , mbd , filteredPds , pvs) ;
}
if (pvs != null ) {
// 将PropertyValues应用给bean
applyPropertyValues(beanName , mbd , bw , pvs) ;
}
}
核心动作就只有 applyPropertyValues
这一个动作,而从方法名上就能 get 到,这个 applyPropertyValues
方法的作用,就是把前面准备好的 **PropertyValues**
对象封装的内容,应用到当前正在创建的 bean 实例上 。
接下来咱进入到 applyPropertyValues
方法中一探究竟。。。呃,这个方法实在是太长了,我们依然是拆解来看吧。
预检查和准备
复制 protected void applyPropertyValues( String beanName , BeanDefinition mbd , BeanWrapper bw , PropertyValues pvs) {
if ( pvs . isEmpty ()) {
return ;
}
if ( System . getSecurityManager () != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw) . setSecurityContext ( getAccessControlContext() );
}
MutablePropertyValues mpvs = null ;
List < PropertyValue > original;
// ......
}
这段很简单啦,如果直接没有要应用的 bean 属性,则直接返回就好,否则它就要准备处理 PropertyValues
了。
重复解析的提前返回
复制 // ......
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
// 判断PropertyValues是否已经解析过了
if ( mpvs . isConverted ()) {
try {
bw . setPropertyValues (mpvs);
return ;
} // catch ......
}
original = mpvs . getPropertyValueList ();
}
else {
original = Arrays . asList ( pvs . getPropertyValues ());
}
// ......
这部分很明显是一个提前返回的动作,if (mpvs.isConverted())
的动作很明显是检查 PropertyValues
是否已经解析过了,如果已经解析过,则直接应用就行,不需要重复解析。
初始化BeanDefinitionValueResolver
复制 // ......
TypeConverter converter = getCustomTypeConverter() ;
if (converter == null ) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver( this , beanName , mbd , converter) ;
// ......
这一段非常短,但这个 BeanDefinitionValueResolver
却很重要!BeanDefinitionValueResolver
的初始化需要传入一个 TypeConverter
,而这个 TypeConverter
是 SpringFramework 中内部用于类型转换的核心 API 。简单的来说,使用 **TypeConverter**
可以将一个 String 类型的数据,转换为特定的所需要的类型的数据 。而 BeanDefinitionValueResolver
就利用 TypeConverter
,完成对 bean 实例中需要注入的属性值进行解析,并适配为 bean 属性所需要的类型(如 String → int ,依赖 bean 的名称转为实际 bean 的引用)。
类型转换
这一部分小册就不着重解释了 ,类型转换不属于我们重点关心的东西,小册在源码的关键位置留了注释,小伙伴们看看就得了。
复制 // ......
// Create a deep copy, resolving any references for values.
List < PropertyValue > deepCopy = new ArrayList <>( original . size ());
boolean resolveNecessary = false ;
// 迭代逐个解析PropertyValue
for ( PropertyValue pv : original) {
// 已经解析过的直接添加
if ( pv . isConverted ()) {
deepCopy . add (pv);
}
else {
String propertyName = pv . getName ();
// 此处取出的值是未经过转换的原始value
Object originalValue = pv . getValue ();
// 此处是 5.2 的一个扩展,如果编程式使用BeanDefinitionBuilder添加自动注入的属性时,
// 会使用类似于自动注入支持的方式处理该属性
if (originalValue == AutowiredPropertyMarker . INSTANCE ) {
Method writeMethod = bw . getPropertyDescriptor (propertyName) . getWriteMethod ();
if (writeMethod == null ) {
throw new IllegalArgumentException( "Autowire marker for property without write method: " + pv) ;
}
originalValue = new DependencyDescriptor( new MethodParameter(writeMethod , 0 ) , true ) ;
}
// 根据originalValue的类型,解析出bean依赖的属性值
// 此处如果是bean的名称,则最终解析出来的是真正的bean对象
Object resolvedValue = valueResolver . resolveValueIfNecessary (pv , originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw . isWritableProperty (propertyName) &&
! PropertyAccessorUtils . isNestedOrIndexedProperty (propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue , propertyName , bw , converter) ;
}
// 此处要对解析前和解析后的数据进行对比
// 如果解析之前与解析之后的值完全一致,则代表不需要解析,或已经解析过了,直接保存
if (resolvedValue == originalValue) {
if (convertible) {
pv . setConvertedValue (convertedValue);
}
deepCopy . add (pv);
}
// 如果String类型转为其他类型(除了集合或数组),则认为它也不需要再解析了
else if (convertible && originalValue instanceof TypedStringValue &&
! ((TypedStringValue) originalValue) . isDynamic () &&
! (convertedValue instanceof Collection || ObjectUtils . isArray (convertedValue))) {
pv . setConvertedValue (convertedValue);
deepCopy . add (pv);
}
// 否则,该字段认定为每次都需要重新解析
else {
resolveNecessary = true ;
deepCopy . add ( new PropertyValue(pv , convertedValue) );
}
}
}
// 如果所有字段都解析完毕,则当前PropertyValues可以标记为已经解析完成,后续不需要重复解析
if (mpvs != null && ! resolveNecessary) {
mpvs . setConverted ();
}
// ......
实际在测试代码中,这个方法压根就没走,都被 AutowiredAnnotationBeanPostProcessor
处理完了,所以这个地方我们一带而过得了。
PropertyValues应用到bean
复制 // ......
// Set our (possibly massaged) deep copy.
try {
bw . setPropertyValues ( new MutablePropertyValues(deepCopy) );
}
catch ( BeansException ex) {
throw new BeanCreationException(
mbd . getResourceDescription() , beanName , "Error setting property values" , ex) ;
}
}
最后一个步骤,这里要把 PropertyValues
中的属性值全部应用到 bean 对象中了。这一部分来回调的源码比较多,最终的落地在 org.springframework.beans.AbstractNestablePropertyAccessor.PropertyHandler#setValue
中,它的其中一个实现类 FieldPropertyHandler
的方法实现如下:
复制 public void setValue(@ Nullable Object value) throws Exception {
try {
ReflectionUtils . makeAccessible ( this . field );
this . field . set ( getWrappedInstance() , value);
}
// catch ......
}
简直简单的不要再简单,反射赋值,简单粗暴。
到这里,整个 populateBean
的属性赋值动作就全部完成了。
1.4 initializeBean
当 bean 的创建过程走到 initializeBean
方法时,此时 bean 中的属性都是齐全的了,但生命周期的回调都还没有回调,接下来我们研究这个部分。
先总体概览一下源码,这里面包含 4 个步骤,均在源码中加以标注:
复制 protected Object initializeBean( String beanName , Object bean , @ Nullable RootBeanDefinition mbd) {
if ( System . getSecurityManager () != null ) {
// ......
}
else {
// 1.4.1 执行Aware回调
invokeAwareMethods(beanName , bean) ;
}
Object wrappedBean = bean;
// 1.4.2 执行BeanPostProcessor的前置回调
if (mbd == null || ! mbd . isSynthetic ()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean , beanName) ;
}
try {
// 1.4.3 执行生命周期回调
invokeInitMethods(beanName , wrappedBean , mbd) ;
}
// catch ......
// 1.4.4 执行BeanPostProcessor的后置回调
if (mbd == null || ! mbd . isSynthetic ()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean , beanName) ;
}
return wrappedBean;
}
下面我们分述这几个步骤。
1.4.1 invokeAwareMethods - 执行Aware回调
invokeAwareMethods(beanName, bean);
这个方法中的定义相当简单,只是判断接口的定义,以及强转后的接口方法调用而已,非常容易理解:
复制 private void invokeAwareMethods( String beanName , Object bean) {
if (bean instanceof Aware) {
// 如果bean实现了BeanNameAware,则强转后调用setBeanName方法注入bean的名称
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean) . setBeanName (beanName);
}
// 如果bean实现了BeanClassLoaderAware,则强转后调用setBeanClassLoader方法注入当前的ClassLoader
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader() ;
if (bcl != null ) {
((BeanClassLoaderAware) bean) . setBeanClassLoader (bcl);
}
}
// 如果bean实现了BeanFactoryAware,则强转后调用setBeanFactory方法注入BeanFactory
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean) . setBeanFactory ( AbstractAutowireCapableBeanFactory . this );
}
}
}
不过这里面有一个问题:有关 ApplicationContext
部分的处理,怎么一个也没有咧???有关这个问题,我们马上在下面就提到了,接着往下来看。
1.4.2 applyBeanPostProcessorsBeforeInitialization
复制 public Object applyBeanPostProcessorsBeforeInitialization( Object existingBean , String beanName)
throws BeansException {
Object result = existingBean;
for ( BeanPostProcessor processor : getBeanPostProcessors() ) {
Object current = processor . postProcessBeforeInitialization (result , beanName);
// 此处做了一个分支控制:如果处理完的结果返回null,则认为停止BeanPostProcessor的处理,返回bean对象
if (current == null ) {
return result;
}
result = current;
}
return result;
}
这个逻辑就很简单了,它会依次执行容器中所有 BeanPostProcessor
的 postProcessBeforeInitialization
方法。不过这里有一个分支控制处理:如果处理完的结果返回 null ,则不再执行后面剩余的 BeanPostProcessor
,直接返回上一个 BeanPostProcessor
处理之后的 bean 对象返回。由此我们可以在此处针对自己项目中某些特定的 bean 搞一些特殊的拦截的处理。
只看这个逻辑还是很简单的吧,所以我们要深入其中,看几个 BeanPostProcessor
的实现。
InitDestroyAnnotationBeanPostProcessor
又要看它了,既然它有收集 bean 的初始化和销毁信息,那这里就肯定有回调的时机咯。这个源码的写法我们在上面已经看过好几个差不多的了:
复制 public Object postProcessBeforeInitialization( Object bean , String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata( bean . getClass()) ;
try {
metadata . invokeInitMethods (bean , beanName);
}
// catch ......
return bean;
}
根据上面分析的内容,我们已经知道,findLifecycleMetadata
方法可以把标注了 @PostConstruct
和 @PreDestroy
注解的方法都取出来,所以这里就相当于回调 **@PostConstruct**
标注的方法 了!
进入到 metadata.invokeInitMethod
方法中:
复制 public void invokeInitMethods( Object target , String beanName) throws Throwable {
Collection < LifecycleElement > checkedInitMethods = this . checkedInitMethods ;
Collection < LifecycleElement > initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this . initMethods );
if ( ! initMethodsToIterate . isEmpty ()) {
for ( LifecycleElement element : initMethodsToIterate) {
// logger ......
element . invoke (target);
}
}
}
又是熟悉的 element.invoke
操作,不过这里就没那么复杂了,点进去看:
复制 public void invoke( Object target) throws Throwable {
ReflectionUtils . makeAccessible ( this . method );
this . method . invoke (target , ( Object []) null );
}
嚯,直接反射调用方法啊,也是非常简单粗暴咯。
另外,根据这个源码中的反射细节,我们也就知道一开始学习 bean 的初始化和销毁方法标注时的规定了:对于 @PostConstruct
和 @PreDestroy
标注的方法来讲,方法的访问修饰符无所谓,但一定不能有方法参数 。
ApplicationContextAwareProcessor
呦,看到类名了,是不是突然明白前面的 Aware
回调为什么没有 ApplicationContext
相关的操作了?是的,这些回调都在这个 ApplicationContextAwareProcessor
中实现了。由此我们可以先得出一个结论:**BeanFactory**
的注入时机比 **ApplicationContext**
早。
接下来我们看源码的实现:
复制 public Object postProcessBeforeInitialization( Object bean , String beanName) throws BeansException {
if ( ! (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
// ......
else {
invokeAwareInterfaces(bean) ;
}
return bean;
}
可以发现,这一个 ApplicationContextAwareProcessor
可以支持 6 个 Aware
接口的回调。至于回调的实现,invokeAwareInterfaces
的操作跟上面 invokeAwareMethods
一模一样,小册就不再贴出啦,小伙伴们可以自行去看一下。
1.4.3 invokeInitMethods - 执行初始化生命周期回调
终于到了我们可能最熟悉的部分了,这里有 InitializingBean
接口的 afterPropertiesSet
方法回调,以及 init-method
的回调:
复制 protected void invokeInitMethods( String beanName , Object bean , @ Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || ! mbd . isExternallyManagedInitMethod ( "afterPropertiesSet" ))) {
// ......
else {
// 回调InitializingBean的afterPropertiesSet方法
((InitializingBean) bean) . afterPropertiesSet ();
}
}
if (mbd != null && bean . getClass () != NullBean . class ) {
String initMethodName = mbd . getInitMethodName ();
if ( StringUtils . hasLength (initMethodName) &&
! (isInitializingBean && "afterPropertiesSet" . equals (initMethodName)) &&
! mbd . isExternallyManagedInitMethod (initMethodName)) {
// 回调init-method方法(同样是反射调用)
invokeCustomInitMethod(beanName , bean , mbd) ;
}
}
}
这部分源码理解起来那是相当的容易了是吧!so 小册也不作过多解释咯。
1.4.4 applyBeanPostProcessorsAfterInitialization
复制 public Object applyBeanPostProcessorsAfterInitialization( Object existingBean , String beanName)
throws BeansException {
Object result = existingB ean;
for ( BeanPostProcessor processor : getBeanPostProcessors() ) {
Object current = processor . postProcessAfterInitialization (result , beanName);
if (current == null ) {
return result;
}
result = current;
}
return result;
}
处理逻辑与 applyBeanPostProcessorsBeforeInitialization
部分几乎一模一样,我们还是来关注几个重要的后置处理的实现。
AbstractAutoProxyCreator
复制 public Object postProcessAfterInitialization(@ Nullable Object bean , String beanName) {
if (bean != null ) {
Object cacheKey = getCacheKey( bean . getClass() , beanName) ;
if ( this . earlyProxyReferences . remove (cacheKey) != bean) {
// 创建代理对象
return wrapIfNecessary(bean , beanName , cacheKey) ;
}
}
return bean;
}
这就是之前我们在学习 BeanPostProcessor
中一直提到的创建代理的核心处理器了,它也是 AOP 创建代理对象的核心实现。由于这个逻辑属于 AOP 的内容,咱回头放到 AOP 章节详细展开。
ApplicationListenerDetector
复制 public Object postProcessAfterInitialization( Object bean , String beanName) {
if (bean instanceof ApplicationListener) {
Boolean flag = this . singletonNames . get (beanName);
if ( Boolean . TRUE . equals (flag)) {
this . applicationContext . addApplicationListener (( ApplicationListener<?> ) bean);
}
// 异常分支处理 ......
}
return bean;
}
这个 ApplicationListenerDetector
我们在上一章的 BeanPostProcessor
初始化阶段还说过一次,它用来关联所有的监听器引用。同样的,监听器在创建的时候,也需要 ApplicationListenerDetector
把这些监听器挂进 ApplicationContext
中,这样这些监听器才可以被事件广播器使用。
1.5 注册销毁时的回调
如果一个 bean 定义的 class 有实现 DisposableBean
接口,或者声明了 @PreDestroy
注解,或者声明了 destroy-method
方法,则会在 doCreateBean
方法的最后一步,注册一个销毁 bean 的回调钩子:
复制 // doCreateBean 最后 ......
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName , bean , mbd) ;
}
// catch ......
return exposedObject;
}
进入 registerDisposableBeanIfNecessary
方法:
复制 protected void registerDisposableBeanIfNecessary( String beanName , Object bean , RootBeanDefinition mbd) {
AccessControlContext acc = ( System . getSecurityManager () != null ? getAccessControlContext() : null );
// 不是原型bean,且有定义销毁类型的方法
if ( ! mbd . isPrototype () && requiresDestruction(bean , mbd) ) {
if ( mbd . isSingleton ()) {
registerDisposableBean(beanName ,
new DisposableBeanAdapter(bean , beanName , mbd , getBeanPostProcessors() , acc)) ;
}
// 处理特殊的scope ......
}
}
可见,通常情况下可以记录销毁 bean 的回调钩子的原则是:单实例 bean ,并且有定义销毁类型的方法 ,而这些销毁类型的方法,就是刚才提到的三种类型,也是早在第 13 章我们就学过的类型。
对于这些定义了销毁类型的方法的 bean ,会记录到一个 disposableBeans
的 Map
中:
复制 private final Map < String , Object > disposableBeans = new LinkedHashMap <>();
public void registerDisposableBean( String beanName , DisposableBean bean) {
synchronized ( this . disposableBeans ) {
this . disposableBeans . put (beanName , bean);
}
}
这个 Map
在下一章的 bean 销毁部分还会提及,小伙伴们可以先留意一下。
到这里,doCreateBean
方法全部执行完毕,一个 bean 已经被成功的创建出来了。
2. SmartInitializingSingleton
在上一章的第 2 节 preInstantiateSingletons
方法中,我们只做了 getBean
方法的全解析,当时在源码的注释中,小册在最后埋了一个伏笔:
复制 else {
// 普通的初始化,就是getBean方法
getBean(beanName) ;
}
}
}
// 初始化的最后阶段 ......
}
这个初始化的最后阶段,是在 SpringFramework 4.1 之后才有的,而支撑这个阶段的核心接口是 SmartInitializingSingleton
。
这个接口在开发中的使用意义不是很大,小伙伴们简单了解下就可以了。
2.1 SmartInitializingSingleton的设计
在 SmartInitializingSingleton
接口的 javadoc 中,可以找到这样的一段话:
This callback variant is somewhat similar to org.springframework.context.event.ContextRefreshedEvent but doesn't require an implementation of org.springframework.context.ApplicationListener, with no need to filter context references across a context hierarchy etc. It also implies a more minimal dependency on just the beans package and is being honored by standalone ListableBeanFactory implementations, not just in an org.springframework.context.ApplicationContext environment.
这个回调变体有点类似于 ContextRefreshedEvent
,但是不需要 ApplicationListener
的实现,不需要在整个上下文层次结构中过滤上下文引用。这也意味着更多对 bean 包的依赖性最小,并且由独立的 ListableBeanFactory
实现兑现,而不仅仅是在 ApplicationContext
环境中。
从这段注释中,我们就可以知道,**SmartInitializingSingleton**
的设计是为了只让 **BeanFactory**
控制的,不需要 **ApplicationContext**
也能实现的 bean 的初始化后处理 。而且从包名上也能看得出来:org.springframework.beans.factory
,嗯,是 beans
包下的,与 context
没关联。
这个地方作者认为没有必要深究它的出现缘由,毕竟对于我们开发者来讲,可供切入框架中的时机越多,灵活度也就越高,重要的我们学习,不重要的我们知道一下就好了。
2.2 SmartInitializingSingleton的回调
复制 else {
getBean(beanName) ;
}
}
}
// Trigger post-initialization callback for all applicable beans...
for ( String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName) ;
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// ......
else {
smartSingleton . afterSingletonsInstantiated ();
}
}
}
}
SmartInitializingSingleton
的回调时机,是所有的非延迟加载的单实例 bean 都初始化完成后,再挨个执行 afterSingletonsInstantiated
方法,调用的方式非常简单,逐个判断就完事了,也没什么好解释的。
3. Lifecycle的回调
在 ApplicationContext
的 refresh
方法最后,初始化完成所有非延迟加载的单实例 bean 之后,会执行 finishRefresh
方法:
复制 protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 清除上下文级别的资源缓存
clearResourceCaches() ;
// Initialize lifecycle processor for this context.
// 为当前ApplicationContext初始化一个生命周期处理器
initLifecycleProcessor() ;
// Propagate refresh to lifecycle processor first.
// 将refresh的动作传播到生命周期处理器
getLifecycleProcessor() . onRefresh ();
// Publish the final event.
// 广播事件
publishEvent( new ContextRefreshedEvent( this )) ;
// Participate in LiveBeansView MBean, if active.
LiveBeansView . registerApplicationContext ( this );
}
可以发现,这里面的处理逻辑还是很有序的,首先把该读取的一些资源缓存都清除掉,然后它初始化了一个生命周期处理器,随后调用它的 onRefresh
方法,接下来广播 ContextRefreshedEvent
事件。而回调 Lifecycle
接口的动作,就发生在这个生命周期处理器中。
3.1 initLifecycleProcessor
复制 protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory() ;
if ( beanFactory . containsLocalBean (LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this . lifecycleProcessor =
beanFactory . getBean (LIFECYCLE_PROCESSOR_BEAN_NAME , LifecycleProcessor . class );
// logger ......
}
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor() ;
defaultProcessor . setBeanFactory (beanFactory);
this . lifecycleProcessor = defaultProcessor;
beanFactory . registerSingleton (LIFECYCLE_PROCESSOR_BEAN_NAME , this . lifecycleProcessor );
// logger ......
}
}
由此可以发现,无论 BeanFactory
中有没有 LifecycleProcessor
,它都会保证最终容器中会有,注意它的实现类是 DefaultLifecycleProcessor
,我们下面会进入它的内部实现。
3.2 onRefresh
复制 public void onRefresh() {
startBeans( true ) ;
this . running = true ;
}
DefaultLifecycleProcessor
的 onRefresh
方法非常简单,就是启动 bean 。继续往下进到源码中:
复制 private void startBeans( boolean autoStartupOnly) {
Map < String , Lifecycle > lifecycleBeans = getLifecycleBeans() ;
Map < Integer , LifecycleGroup > phases = new HashMap <>();
lifecycleBeans . forEach ((beanName , bean) -> {
// 注意此处,如果autoStartupOnly为true,则不会执行
if ( ! autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean) . isAutoStartup ())) {
int phase = getPhase(bean) ;
LifecycleGroup group = phases . get (phase);
if (group == null ) {
group = new LifecycleGroup(phase , this . timeoutPerShutdownPhase , lifecycleBeans , autoStartupOnly) ;
phases . put (phase , group);
}
group . add (beanName , bean);
}
});
if ( ! phases . isEmpty ()) {
List < Integer > keys = new ArrayList <>( phases . keySet ());
Collections . sort (keys);
for ( Integer key : keys) {
// 依次调用Lifecycle的start方法
phases . get (key) . start ();
}
}
}
这里面就是一个一个调用 Lifecycle
的 start
方法的位置了,但请小伙伴们注意一点:由于 onRefresh
方法中调用的 startBeans(true);
传入的参数是 true ,lifecycleBeans.forEach
部分不会执行,所以在该阶段不会回调 Lifecycle
的 start
方法!
3.3 ApplicationContext#start
那这些 Lifecycle
的 start
方法什么时候才能被调用呢?我们回到测试代码中:
复制 ctx . refresh ();
System . out . println ( "================IOC容器刷新完毕==================" );
ctx . start ();
// ---------AbstractApplicationContext----------
public void start() {
getLifecycleProcessor() . start ();
publishEvent( new ContextStartedEvent( this )) ;
}
// ---------DefaultLifecycleProcessor-----------
public void start() {
startBeans( false ) ;
this . running = true ;
}
下面我们主动的调用了 ctx.start()
方法,而 ApplicationContext
的 start
方法中调用的 LifecycleProcessor
,会最终调用 startBeans(false);
,激活 Lifecycle
回调的逻辑。
好,了解到 Lifecycle
真正回调的时机,下面我们还是看看 SpringFramework 是如何回调 Lifecycle
的。
3.3.1 startBeans
复制 private void startBeans( boolean autoStartupOnly) {
Map < String , Lifecycle > lifecycleBeans = getLifecycleBeans() ;
Map < Integer , LifecycleGroup > phases = new HashMap <>();
lifecycleBeans . forEach ((beanName , bean) -> {
if ( ! autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean) . isAutoStartup ())) {
// 此处的phase可类比Order
int phase = getPhase(bean) ;
LifecycleGroup group = phases . get (phase);
if (group == null ) {
// 不同的phase分到不同的group中
group = new LifecycleGroup(phase , this . timeoutPerShutdownPhase , lifecycleBeans , autoStartupOnly) ;
phases . put (phase , group);
}
group . add (beanName , bean);
}
});
// ......
我们把 startBeans
方法分为两部分来看,前半段的操作很明显是一个分组的动作。这里面的 phase
可以类比为 Order
,LifecycleGroup
可以简单的理解为 List<Lifecycle>
。所以这个过程很明显,就是将所有的 **Lifecycle**
按照不同的 **phase**
分组 而已。
3.3.2 start
复制 // ......
if ( ! phases . isEmpty ()) {
List < Integer > keys = new ArrayList <>( phases . keySet ());
Collections . sort (keys);
for ( Integer key : keys) {
//
phases . get (key) . start ();
}
}
}
分组之后,它会根据不同的 phase
排序后依次执行,而执行的 start
方法看上去比较复杂,最终还是调用 Lifecycle
的 start
方法:
复制 public void start() {
if ( this . members . isEmpty ()) {
return ;
}
// logger ......
Collections . sort ( this . members );
for ( LifecycleGroupMember member : this . members ) {
doStart( this . lifecycleBeans , member . name , this . autoStartupOnly ) ;
}
}
private void doStart( Map< String , ? extends Lifecycle > lifecycleBeans , String beanName , boolean autoStartupOnly) {
Lifecycle bean = lifecycleBeans . remove (beanName);
if (bean != null && bean != this ) {
String [] dependenciesForBean = getBeanFactory() . getDependenciesForBean (beanName);
for ( String dependency : dependenciesForBean) {
doStart(lifecycleBeans , dependency , autoStartupOnly) ;
}
if ( ! bean . isRunning () &&
( ! autoStartupOnly || ! (bean instanceof SmartLifecycle) || ((SmartLifecycle) bean) . isAutoStartup ())) {
// logger ......
try {
// 【调用实现了Lifecycle接口的bean】
bean . start ();
}
// catch ......
}
}
}
等所有 Lifecycle
都执行完毕,一个 bean 的完整初始化生命周期也就结束了。
4. 总结
bean 对象创建完成后,会进行属性赋值、组件依赖注入,以及初始化阶段的方法回调。在 **populateBean**
属性赋值阶段,会事先收集好 bean 中标注了依赖注入的注解( **@Autowired**
、 **@Value**
、 **@Resource**
、 **@Inject**
),之后会借助后置处理器,回调 **postProcessProperties**
方法实现依赖注入。
属性赋值和依赖注入之后,会回调执行 bean 的初始化方法,以及后置处理器的逻辑:首先会执行 Aware 相关的回调注入,之后执行后置处理器的前置回调,在后置处理器的前置方法中,会回调 bean 中标注了 **@PostConstruct**
注解的方法,所有的后置处理器前置回调后,会执行 **InitializingBean**
的 **afterPropertiesSet**
方法,随后是 **init-method**
指定的方法,等这些 bean 的初始化方法都回调完毕后,最后执行后置处理器的后置回调。
全部的 bean 初始化结束后, **ApplicationContext**
的 **start**
方法触发时,会触发实现了 **Lifecycle**
接口的 bean 的 **start**
方法。