Spring解析之IoC:bean的加载(三)
前言
计划赶不上变化,原本年前准备将这个主题告一段落,但各种工作之外的事接踵而至,且剩下的工作量依然超过我的预期,只能拖到现在,前段时间接了商业化广告的活,源码看得多了自己写时总不自觉的按更高的标准要求自己,一遍遍的修改重构,这可能就是所谓的潜移默化吧
bean
加载三部曲中的第一部按照doGetBean(String, Class<T>, Object[], boolean)
自上而下的代码结构将加载分为if-else
两段,前段在getBean
显式调用时返回单例对象以及自定义FactoryBean
生成bean
时调用,其中的重点为部分解决循环依赖的“三层缓存”和getObjectForBeanInstance(Object, String, String, RootBeanDefinition)
,后段由初始化过程中隐式调用以及获得多例对象时调用,在第二部中介绍了隐式调用的整个流程,最后剩下createBean(String, RootBeanDefinition, Object[])
核心创建bean
尚未分析,本篇文章就与这部分内容相关
由于只剩下createBean
这个核心方法了,那么我们还是像前面将核心方法分成几块讲解
标注1生成最终能实例化的
Class
类型,但并没有根据Class
实例化出对象图2. 解析出可实例化的Class
在分析解析XML并将解析后内容封装成
GenericBeanDefinition
过程中曾今说过<bean>
中class
属性与GenericBeanDefinition
父类AbstractBeanDefinition
中Object beanClass
对应,这里mbd.hasBeanClass()
就是判断beanClass
是否instanceof Class
,如果是直接返回,因为我们要的就是Class
类型,不是的话最终调用doResolveBeanClass(RootBeanDefinition, Class<?>)
,该方法依然是个中转方法,主要根据传入的typesToMatch
生成特定的ClassLoader
,之后还要调用RootBeanDefinition#resolveBeanClass
,根据特定的加载器或者默认加载器加载出class
属性对应的Class
对象,其生成Class
的动作又委派给工具类ClassUtils
图3. 使用ClassUtils创建出Class
我们将创建
Class
流程分成三部分:第一部分主要处理一些“原始”数据类型,举个简单的例子我在XML中配置如下
<bean id="myInt" class="java.lang.Integer">
我定义的对象就是“原始”数据类型,这种类型的Class处理就由第一部分负责,具体是怎么做的呢,实际上是两个Map
,一个是resolvePrimitiveClassName(String)
中隐含的primitiveTypeNameMap
,另一个就是commonClassCache
,对应的代码给大家看一下
在
ClassUtils
加载时就会将基本数据类型,基本数据类型对应的包装类型,基本数据类型数组和包装类型数组等Class
放入两个Map
中,如果我们配置的类属于其中的一个直接返回对应的Class
即可。图3红框2内代码处理的类型为java.lang.String[]
、[Ljava.lang.String;
和[[Ljava.lang.String;
,第一个我可以尝试模拟出来,后两个实在没搞明白怎么模拟,有知道的读者麻烦告知。如果之前根据typesToMatch
生成了特定的类加载器就用这个ClassLoader
加载Class
,否则使用默认加载器,默认类加载是首先使用当前线程类加载器,如果还是没有获取到使用当前类的类加载器。这一系列的操作后RootBeanDefinition
中的beanClass
属性除了异常情况就都是对应<bean>
生成对象的Class
了回到图1标注2代码是对
<lookup-method>
和<replaced-method>
两种method injection
方式的预处理,在Spring解析之IoC:<bean>解析及Bean的注册中我们没有详细阐述两个标签的解析存储过程,在这里大致了解一下,两个标签解析后分别封装在LookupOverride
和ReplaceOverride
中,两个对象都继承自抽象父类MethodOverride
,而多个该类对象又存放在AbstractBeanDefinition
成员变量MethodOverrides methodOverrides
中,下面我已<lookup-method>
举个例子,说明下此类标签的用法已经解决的问题<lookup-method>
标签最重要的一个用途就是在单例对象内注入一个多例对象,我们知道构造器注入和setter
注入是两种最常用的注入方式,但如果说到实现单例对象中注入多例对象需求,这两种注入方式都鞭长莫及,因为在Spring创建出单例对象时相关的依赖注入流程都已经完成,也就是说依赖的对象只能注入一次,为了解决这个问题,Spring提出了method injection
方法注入,我们先来例子让大家有个直观的认识。首先定义一个单例对象SingletonService
图5. SingletonService
该类是一个抽象类,存在返回多例对象的抽象方法,再定义一个多例对象的抽象接口
Prototype
图6. Prototype接口
有接口了必然有就有一个或多个实现,这里为了简便只提供了一个实现类
图7. Prototype接口的实现类MyPrototype
在XML中进行
<bean>
配置图8. 相关XML配置
实现类
scope = prototype
否则就失去了动态注入的意义了,lookup-method
中name
获得多例对象的抽象方法名称,bean
为返回bean
的类型,比如这里就是任何实现了Prototype
接口的实现类id/name
,如果读者想跟深入了解的话,我给出一篇文章Method Injection。说了一堆做铺垫再来看图1标注2做了什么图9. AbstractBeanDefinition的prepareMethodOverrides()
上面说过所有的方法注入标签都存放在
methodOverrides
,遍历所有的MethodOverride
,根据<lookup-method>
或<replaced-method>
中抽象方法名(name
属性的值)和抽象类中所有同名的抽象方法比较,算出符合name
的抽象方法数量,为什么要这样呢?我试验了一下,结果是可能存在同名重载方法,最简单的例子就是同名抽象方法但参数不同,但<lookup-method>
或<replaced-method>
中有无法配置抽象方法的参数,所以需要全部计数。那为什么但只存在一个符合抽象方式时setOverloaded(false)
呢?其实读者可以将这里的判断和下面的使用分为两部分考虑,如果存在多个重载方法,那么使用时必定要再次判断到底配置的是哪一个,如果只有一个符合要求这里加上一个标识,在下面使用的时候就省去了再次判断的开销图1的标注3主要的目的在注释上写的还是比较清楚的,给用户一个机会可以返回目标对象的代理实例,如果返回不为
null
,即返回了代理对象就直接返回,在正式说这部分逻辑之前还得先补充一个知识,在前面说过Spring提供后处理器接口BeanPostProcessor
,提供了在初始化对象后修改实例的能力,该接口有很多子接口,后面有机会会一一介绍,现在先说一种InstantiationAwareBeanPostProcessor
,除了父类提供的两个待实现接口外又提供了另外三种,分别为Object postProcessBeforeInstantiation(Class<?>, String)
、boolean postProcessAfterInstantiation(Object, String)
和PropertyValues postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)
,为了更好的说明还是举个例子图10. InstantiationAwareBeanPostProcessorImpl
InstantiationAwareBeanPostProcessorImpl
实现了接口所有的方法,并做了一些打印以便观看现象,在XML中也加上简单的配置
<bean id="student" class="com.xiaomi.bean.Student">
<property name="name" value="zhangsan"></property>
</bean>
<bean id="instantiationAwareBeanPostProcessor" class="com.xiaomi.bean.InstantiationAwareBeanPostProcessorImpl"></bean>
运行并两次获得Student
实例打印,结果如下
很明显在生成
Student
实例前调用了postProcessBeforeInstantiation
,那么我们可以在这个时候对目标对象进行一定的包装或者处理,达到类似AOP的目的,之后真正创建了Student
实例,创建完成进行属性的注入,在注入之前会调用postProcessPropertyValues
,在该方法中我们将原本注入的zhangsan
替换成了lisi
,“调包”后Spring调用了setter
进行属性注入,最后才调用父接口BeanPostProcessor
的两个方法,这个顺序之前已经说过,没什么意外的。我们获得了两次Student
对象由打印语句发现实现InstantiationAwareBeanPostProcessor
只会在创建对象前调用一次,当然,如果这里Student
是多例,自然就会被第二次处理。讲到这里我们将postProcessBeforeInstantiation
注释去除,在运行一遍看看结果有什么不同图12. 去除postProcessBeforeInstantiation注释部分去除运行结果
我们发现只剩下
postProcessBeforeInstantiation
和postProcessAfterInitialization
两个方法的调用(Student
构造器也是在postProcessBeforeInstantiation
中显式调用的,而不是Spring容器创建对象时默认调用),为什么会出现这种情况,其实我们回到源码看一下处理逻辑就都清楚了图13. AbstractAutowireCapableBeanFactory的resolveBeforeInstantiation(String, RootBeanDefinition)
上图代码对应图1的标注3,在初始化时Spring会检测是否存在自定义类实现了
InstantiationAwareBeanPostProcessor
接口,如果存在会将DefaultListableBeanFactory
中成员变量hasInstantiationAwareBeanPostProcessors
置为true
,这里的boolean hasInstantiationAwareBeanPostProcessors()
判断通过调用第一个下划线方法图14. AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsBeforeInstantiation(Class<?>, String)
逻辑很简单,首先获得所有后处理器,判断其中所有实现
InstantiationAwareBeanPostProcessor
的类,进而调用它的postProcessBeforeInstantiation
,最后将我们自己实现方法的返回值返回。resolveBeforeInstantiation
根据是否返回对象(代理)判断是否调用applyBeanPostProcessorsAfterInitialization(RootBeanDefinition, String)
图15. AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsAfterInitialization(Object, String)
方法中调用了
BeanPostProcessor
的postProcessAfterInitialization(Object, String)
,再看看图1的总流程,如果bean != null
就直接返回,联想上面的例子bean != null
实际上就是我们生成代理的情况,那就是说如果有代理直接返回代理对象,且只会调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
和BeanPostProcessor#postProcessAfterInitialization
,所表现出来的结果正是例子图12的样子,既然调了包返回了代理那就没有必要再创建原始的目标类了,否则进入图1标注4创建目标类实例的代码,代码清单2
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// (1)
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// (2)
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
// (3)
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// (4)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// (5)
addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// (6)
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// (7)
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// (8)
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(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.");
}
}
}
}
// Register bean as disposable.
try {
// (9)
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
Spring首先创建了一个bean
的包装类,按照官方文档上的说法提供该类的好处有:1.提供了设置单个和成块属性值的功能,可以获得属性的descriptors
,查询属性是否可读可写;2.支持属性的无限嵌套;2.具有不改变目标类代码情况下,添加PropertyChangeListeners
和VetoableChangeListeners
功能等。还想深入了解该类的读者可以看Bean manipulation and the BeanWrapper。如果缓存中已经存在我们后续要操作的BeanWrapper
,直接移除取出做后续处理如标注1,如果暂时不存在该对象标注2处代码进行创建,此处是getBean
核心逻辑之一,Spring根据创建对象方式的不同又在该方法内部分为三部分:1.根据factory-method工厂方法进行创建;2.匹配一个或多个参数的有参构造器创建;3.默认无参进行实例化。后续会用专门的文章对这三种方式的创建流程进行分析。
到目前为止我们已经遇过两个后处理器相关的接口,一个是BeanPostProcessor
,另一个是它的子接口InstantiationAwareBeanPostProcessor
,标注3又会引出一个BeanPostProcessor
的子接口MergedBeanDefinitionPostProcessor
,除了父接口的两个方法外还需实现该接口的类给出postProcessMergedBeanDefinition(RootBeanDefinition, Class<?>, String)
,前面我们说过如果<bean>
存在父子关系,Spring在解析之后会将父子关系的<bean>
映射成为RootBeanDefinition
,那么该后处理器及待实现方法就是在做RootBeanDefinition
的后处理工作
标注4根据:1.是否单例;2.是否允许循环引用标志;3.beanName
对应的bean
是否正在创建中三个条件决定是否允许“早期单例暴露”。同样的,我们说过Spring中部分解决循环依赖的第三级缓存正是标注5的代码,如果判断允许“早期单例暴露”就将创建该单例对象的ObjectFactory
存入三级缓存singletonFactories
。当要获得单例对象时Spring会调用自定义ObjectFactory
的getObject()
,其实就是这里的getEarlyBeanReference(String, RootBeanDefinition, Object)
这里又出现一个新的后处理器
SmartInstantiationAwareBeanPostProcessor
,它继承自InstantiationAwareBeanPostProcessor
,新提供了三个待实现方法:1.Class<?> predictBeanType(Class, String)
用于预测返回bean
的Class
类型,一般在隐式初始化时调用;2.Constructor<?>[] determineCandidateConstructors(Class<?>, String)
存在多个构造器时用于决定使用哪个进行类的初始化,在上面说过的通过有参构造器创建对象时调用;3.Object getEarlyBeanReference(Object, String)
用于获得早期暴露的单例对象引用,和MergedBeanDefinitionPostProcessor
类似,一般不需要我们人为扩展,而是Spring内部自己使用。标注6主要是对BeanWrapper
进行属性的填充,代码清单3
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
// (1)
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// 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.
boolean continueWithPropertyPopulation = true;
// (2)
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
// (3)
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
// (4)
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// (5)
applyPropertyValues(beanName, mbd, bw, pvs);
}
Spring初始化解析XML配置文件时,所有的<property>
会放入PropertyValue
的集合中,集合又被封装入MutablePropertyValues
对象中。标注1的判断逻辑是,如果不存在是<bean>
对应实体BeanWrapper
但还存在解析出的属性,肯定出现问题了,抛出异常;如果不存在实体也不存在属性,那也没有继续往下解析的必要了,直接返回。标注2又一次用到了上面讲过的InstantiationAwareBeanPostProcessor
,如果存在实现该接口后处理器,则调用boolean postProcessAfterInstantiation(Object, String)
,进行对象实例创建后的处理,这里依然存在一个短路操作,如果方法返回false,continueWithPropertyPopulation
为假,如果该值非真,也无需进行后处理器对于属性处理等后续操作了。标注3很明显涉及按名称、按类型两种属性注入方式,后续会有专门文章分析注入原理,这里不做阐述。标注4根据是否有InstantiationAwareBeanPostProcessor
或依赖检查标识判断是否进行属性的“调包”处理,处理的过程就是InstantiationAwareBeanPostProcessor
自有方法的最后一个PropertyValues postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)
。到这里Spring得到了所有需要填充的属性(两种方式注入的、后处理器调包的),最后调用标注5处代码真正将属性设置进BeanWrapper
对象中,代码清单4
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (System.getSecurityManager() != null) {
if (bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
}
// (1)
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
// (2)
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// (3)
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
// (4)
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
// (5)
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// (6)
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
// (7)
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));
}
}
}
// (8)
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
// (9)
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
标注1首先判断所有属性整体是否都被转换,如果是就不需要下面的步骤,直接赋值返回;如果并不是所有属性已经转换过,就会首先按标注2获取用户自定义的类型转换器。标注3创建了新集合用于存放转换后的结果,之后遍历每一个属性并依次判断转换与否,没有转换则标注4根据上面创建的解析器valueResolver
对该值进行解析,我们知道除了最普通的String外Spring支持多种形式的属性配置,该方法中就包含了几乎所有类型属性的解析流程,这里给出一张表格涉及所有解析的类型已经该类型在读取XML时对应的封装类型
真实类型 | 封装类型 |
---|---|
Array |
ManagedArray |
List |
ManagedList |
Set |
ManagedSet |
Map |
ManagedMap |
Bean |
BeanDefinitionHolder |
ref引用Bean |
RuntimeBeanReference |
idref |
RuntimeBeanNameReference |
Properties |
ManagedProperties |
String |
TypedStringValue |
SPEL表达式 |
TypedStringValue |
如果判断该属性是可转换的convertible = true
,就会开始标注5的自定义转换器的转换,如果原始值originalValue
与经过Spring内置解析器解析后的值resolvedValue
相同,且可转换标识convertible
为真说明必定经过了自定义转换的步骤(不管是否真的转换过),此时用最新的convertedValue
替换老值,如果标识6所示。实际上我觉得标注6和7具有相同的目的,只要convertible
为真就说明最新的值必然为convertedValue
,那也必然要更新属性封装对象对应字段了。标注8将属性对象设为整体已转化,与方法一开始根据此判断直接返回还是开始转换相呼应。标注9终于将解析后数组封装入MutablePropertyValues
,再塞入BeanWrapper
中,至此创建对象中的属性填充流程分析完毕
接着代码清单2分析看标注7,“初始化”Bean
该方法严格意义上来说并不是做了
Bean
的初始化,因为此时参数的bean
已经是实例化完成的对象了,只不过该对象还在Spring内部,并没有暴露给用户,方法内主要做了三件事:1.感知类对象相关属性的设置;2.后处理器方法的处理;3.init-method
属性的处理。我们一个个来看,如果bean
实现了BeanNameAware
、BeanClassLoaderAware
和BeanFactoryAware
三种Aware
接口中的一个或多个,则调用对应的实现方法,虽然大家可能对这三者不太熟悉,另一个Aware
接口ApplicatonContextAware
相信大家都用过,该接口的setApplicationContext(ApplicationContext)
能让我们得到Spring的上下文对象,ApplicatonContextAware
和这里的三个接口处理方式如出一辙,只是触发时机不同,前者是在bean
后处理阶段触发,后者则是在这里的Spring容器生命周期初始阶段红线2又碰到
bean
后处理器了,后处理器有多种变体,上面提到过InstantiationAwareBeanPostProcessor
和SmartInstantiationAwareBeanPostProcessor
,并且在Spring解析之IoC:bean的加载(一)中也用例子的形式详解了BeanPostProcessor
的用法,有了前面的基础这里后处理器也就非常好理解了,标注2和4分别对应了BeanPostProcessor
的Object postProcessBeforeInitialization(Object, String)
和Object postProcessAfterInitialization(Object, String)
,方法内会遍历所有实现BeanPostProcessor
接口的类调用每个类的上述两个方法。同样的在Spring解析之IoC:bean的加载(一)的BeanPostProcessor
例子中我们曾经说过后处理器的before/after
是相对于实现了InitializingBean
接口afterPropertiesSet()
方法的执行时刻来说的,那么看图中标注3不是正处在前后方法中间吗?我们有理由猜测invokeInitMethods(String, Object, RootBeanDefinition)
就是对于afterPropertiesSet()
的处理图18. AbstractAutowireCapableBeanFactory的invokeInitMethods(String, Object, RootBeanDefinition)
横线代码验证了我们的猜测,但是我们发现除了调用
afterPropertiesSet()
外还有一处红框内的逻辑没有想到。之前说过Spring提供了三对在bean
初始化和销毁时进行自定义操作的手段:1.@PostConstruct/@PreDestory
;2.<bean>
的init-method/destroy-method
属性;3.实现InitializingBean/DisposableBean
接口,这段代码就是针对第二种情况进行的处理,方法invokeCustomInitMethod(String, Object, RootBeanDefinition)
内部做了一些权限控制后得到配置init-method
的Method
对象,最终通过反射调用该方法初始化
bean
方法分析完毕,我们回到图17从宏观看看各个流程的步骤,其实这就是Spring容器中bean
生命周期那张图的执行流程图19. Spring中Bean的生命周期
Instantiate
对应代码清单2标注2instanceWrapper = createBean(beanName, mbd, args);
第一次创建bean
Popluate properties
对应代码清单3整个属性填充过程BeanNameAware's setBeanName()
对应图17invokeAwareMethods(String, Object)
处理第一个BeanNameAware
流程BeanFactoryAware's setBeanFactory()
对应图17invokeAwareMethods(String, Object)
处理第三个BeanFactoryAware
流程Pre-initializatioin beanPostProcessors
对应图17标注2代码applyBeanPostProcessorsBeforeInitialization(Object, String)
InitializingBean's afterPropertiesSet()
对应图18红线处逻辑Call custom init-method
对应图18红框内代码Post-initialization beanPostProcessors
对应图17标注4代码applyBeanPostProcessorsAfterInitialization(Object, String)
生命周期中的最后两个状态虽然现在没有遇到,但大家看名字就很明显9与6InitializingBean
接口对应,一个初始化一个销毁;10destroy-method
属性和7init-method
对应。记得刚学习Spring时,这个生命周期是永远记不住的知识点,但整个源码分析下来就清清爽爽了
回到主线代码清单2,标注8处代码看上去一大堆,实际这段被执行到的可能性很小,earlySingleton = true
会调用我们曾今说的Object getSingleton(String, boolean)
,我们将方法放在现在的“语境”中再分析一下
读者需要知道的是,这段代码在
new ClassPathXmlApplicationContext()
隐式调用和getBean
多例对象时才有可能调用,对于多例来说earlySingletonExposure = false
,意味着代码不会执行;对于隐式调用allowEarlyReference = false
说明红框处内的代码不会执行,再结合代码清单2标注5addSingletonFactory(String, ObjectFactory)
可以推得只存在singletonObjects
中已有beanName
对应对象这一种可能,整个逻辑代码才会往下执行,介于此该流程就不继续往下分析了。最后看下代码清单2标注9图21. AbstractBeanFactory的registerDisposableBeanIfNecessary(String, Object, RootBeanDefinition)
该方法的主要作用是对实现
Disposable
接口的对象进行注册,注意,这里只是注册,因为销毁必定是在容器关闭时调用的,而这里所有的一切都是对象初始化流程,所以只能是注册,并且只有单例对象且实现Disposable
接口的destroy()
或者实现DestructionAwareBeanPostProcessor
接口的postProcessBeforeDestruction(Object, String)
才会真正注册。注册分为两大块,单例的和自定义scope
的。单例对象销毁注册调用registerDisposableBean(String, DisposableBean)
,将beanName-bean
映射放入Map<String, Object> disposableBeans
即结束;自定义scope
由于需要实现Scope
接口,其中就包含这里的registerDestructionCallback(String, Runnable)
。至此Spring获取bean
逻辑基本讲解完毕,阶段性胜利,哈哈