Spring IoC 属性赋值阶段
前言
本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT
版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。
本篇文章主要介绍 Spring IoC 容器中 bean
的属性赋值阶段。
正文
我们在Spring IoC bean 的创建一文中分析创建 bean
实例的主要流程,此时创建出来的 bean
还是个属性未赋值的实例,在创建完之后会进入 populateBean()
方法,即进入属性赋值阶段。我们简单回顾一下,上次分析过的 doCreateBean()
方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
// 实例化 bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 如果bean的作用域是singleton,则需要移除未完成的FactoryBean实例的缓存
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 通过构造函数反射创建bean的实例,但是属性并未赋值,见下文详解
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 获取bean的实例
final Object bean = instanceWrapper.getWrappedInstance();
// 获取bean的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// BeanDefinition 合并后的回调,见下文详解
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
// 省略异常处理...
mbd.postProcessed = true;
}
}
// bean的作用域是单例 && 允许循环引用 && 当前bean正在创建中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
// 如果允许bean提前曝光
if (earlySingletonExposure) {
// 将beanName和ObjectFactory形成的key-value对放入singletonFactories缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 给 bean 的属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略部分代码
}
属性赋值
AbstractAutowireCapableBeanFactory#populateBean
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 {
return;
}
}
// 给InstantiationAwareBeanPostProcessors最后一次机会在属性设置前来改变bean
// 例如:可以用来支持属性注入的类型
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 这里会调用bean实例化后的生命周期回调,返回false会跳过下面的属性赋值阶段
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// 获取PropertyValues
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 获取依赖注入类型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 如果依赖注入类型是 byName 或者 byType
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 赋值pvs到可修改的MutablePropertyValues
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根据名称自动注入,见下文详解
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根据类型自动注入,见下文详解
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 是否有注册InstantiationAwareBeanPostProcessors的实现类
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 遍历并找到InstantiationAwareBeanPostProcessor的实现类,调用处理属性值的后置处理方法
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
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);
// 如果属性值的后置处理方法返回null,直接返回,不会进行底下的属性值应用阶段
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
// 属性填充,见下文详解
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
上面方法首先会调用 bean
的实例化后生命周期回调方法,如果返回 false
会跳过下面的属性赋值阶段。关于 InstantiationAwareBeanPostProcessors
接口在Spring IoC bean 的创建一文中介绍过,这里不再赘述。接着判断是否是按 名称 或者 类型 自动注入属性并填入 newPvs
中,接着调用 bean
属性填充前的生命周期回调。属性填充前生命周期回调方法有两个 postProcessProperties()
和 postProcessPropertyValues()
,第一个是 Spring 5.1 新加的,后面的是老的,已经被标记为过时;首先会调用 postProcessProperties()
如果返回空调用 postProcessPropertyValues()
,否则直接使用返回的 PropertyValues
;postProcessPropertyValues()
如果返回空会直接跳过属性填充阶段,不为空直接使用返回的 PropertyValues
。
按照名称依赖注入
AbstractAutowireCapableBeanFactory#autowireByName
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 寻找bw中需要依赖注入的属性名称
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 遍历需要注入的bean
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
// 调用getBean()方法获取bean
Object bean = getBean(propertyName);
// 将需要注入bean的实例加入到pvs
pvs.add(propertyName, bean);
// 注册依赖关系
registerDependentBean(propertyName, beanName);
}
}
}
上面的方法很简单,就是寻找 bean
的非简单类型并且不存在于 mbd.getPropertyValues()
中的属性,然后遍历调用 getBean()
方法去获取实例,完成注入。
非简单类型就是指除去8个原始类型、String类型、Number类型、Date类型、URL类型、URI类型的其它类型。
registerDependentBean()
方法在Spring IoC bean 的加载一文中有分析过,这里不再赘述。
按照类型依赖注入
AbstractAutowireCapableBeanFactory#autowireByType
protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 获取bean中非简单属性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// 根据类型注入永远不要注入Object类型,你细细地品一下
if (Object.class != pd.getPropertyType()) {
// 获取属性的可写方法,一般是set方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 依赖解决,最后返回符合条件需要注入的bean实例
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 需要注入的bean实例不为空,加入到pvc
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 注册依赖关系
registerDependentBean(autowiredBeanName, beanName);
}
autowiredBeanNames.clear();
}
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
上面方法中的 resolveDependency()
方法在Spring IoC bean 的创建一文中介绍过,这里不再赘述。
属性赋值
AbstractAutowireCapableBeanFactory#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;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
// 快捷方式,如果属性已经转换过,直接填充进BeanWrapper
if (mpvs.isConverted()) {
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());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
// 获取对应的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 创建深拷贝,解决引用的问题
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// 遍历属性,将属性转换为对应的类型
for (PropertyValue pv : original) {
// 如果pv类型转换过,直接添加进deepCopy
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
// 进行转换
// 拿到pv原始属性名和属性值
String propertyName = pv.getName();
Object originalValue = pv.getValue();
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);
}
// 进行类型转换
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);
}
// 在合并的BeanDefinition中存储转换后的值,以避免为每个创建的bean实例重新转换
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
} 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));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
try {
// 填充bean属性值
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
} catch (BeansException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
上面代码中的 bw.setPropertyValues()
方法最终会调用 BeanWrapperImpl#setVlaue()
方法,如下:
public void setValue(final @Nullable Object value) throws Exception {
// 这里一般就是setter方法
final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor)this.pd).getWriteMethodForActualAccess() : this.pd.getWriteMethod());
// 利用反射调用setter方法给属性赋值
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(getWrappedInstance(), value);
}
下图是我 debug 时的截图,可以看到基本上就是在调用属性的 setter
方法:
注意:没有
setter
方法时会抛出异常。
总结
本篇文章主要分析了 Spring IoC 的属性赋值阶段的流程,Spring 在此阶段也提供了2个扩展点;分别是 bean
的实例化后和属性赋值前,即 InstantiationAwareBeanPostProcessor
接口的 postProcessAfterInstantiation()
方法和 postProcessProperties()
方法。需要注意的是在 XML 中配置的 autowire
属性,不管是 byName
还是 byType
都需要 setter
方法,但是我们平时在使用 @Autowire
注解时并不需要 settter
方法,原因会在分析 @Autowire
注解时讲述。
最后,我模仿 Spring 写了一个精简版,代码会持续更新。地址:https://github.com/leisurexi/tiny-spring。