首先我们要明确,Spring 在创建一个 bean 实例时,会先创建一个属性值为 null 的实例,然后再进行一个赋值。在上一篇中已经对创建实例的流程进行了一个详细的分析,在这一章中我们继续来看属性注入这一块的内容。
首先深入 doCreateBean() 方法中的 AbstractAutowireCapableBeanFactory.populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 实例包装类的非空判断
if (bw == null) {
// ...
}
// 前置处理(如果需要的话)
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// ...
}
// 这里就比较关键, 会获取到 beanDefinition 中的属性值列表
// 这个属性列表也就对应了在 <bean> 下定义的所有 <property>
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 获取到自动装配的模式
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;
}
// 判断是否拥有后置处理器
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 判断是否进行依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
// 后置处理
}
if (needsDepCheck) {
// 依赖校验
}
if (pvs != null) {
// 将beanName、beanDefinition、bean实例包装类、属性值包装类作为参数
// 执行属性注入的逻辑
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
深入 AbstractAutowireCapableBeanFactory.applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
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;
// 若pvs是MutablePropertyValues类型
if (pvs instanceof MutablePropertyValues) {
// 强制类型转换, 从 PropertyValues -> MutablePropertyValues
mpvs = (MutablePropertyValues) pvs;
// 属性值类型是否已经被转换
// 若已经被转换 return true
// 若需要转换 return false
// 就比如我们在xml中定义了年龄字段的值为 "21", 是个字符串类型
// 但是类中年龄字段声明为int
// 因此就需要一个类型转换
if (mpvs.isConverted()) { // 如果已经被转换, 就直接进行属性值注入了
try {
// 在包装类中注入属性值列表
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
// 异常处理...
}
}
// 获取到原属性值列表
original = mpvs.getPropertyValueList();
}
else { //若pvs不是MutablePropertyValues类型, 那么会通过Arrays这个工具类获取到原属性值列表
original = Arrays.asList(pvs.getPropertyValues());
}
// 尝试获取到 AbstractBeanFactory 中封装的类型转换器, 默认为 null
// AbstractBeanFactory 它是 DefaultListableBeanFactory 的父类
// 当我们对 DefaultListableBeanFactory 进行扩展时, 可以指定自定义的类型转换器
TypeConverter converter = getCustomTypeConverter();
// 若未成功获取到, 就将 BeanWrapper 实例赋值给类型转换器的引用
// BeanWrapper实例内部封装了一个TypeConvertDelegate用于属性的转换逻辑
if (converter == null) {
converter = bw;
}
// 创建出BeanDefinition的属性值解析器
// 这个属性解析器内部封装了 BeanFactory、BeanDefinition、TypeConverter、BeanWrapperImpl
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 创建一个深拷贝副本,它会保存转换后的属性值实体
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// 遍历属性值列表, 对每一个属性的pv键值对进行转换处理
// 并添加到深拷贝副本中
for (PropertyValue pv : original) {
// 已经进行了类型转换
// 就直接添加到深拷贝副本中
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
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);
}
// 通过属性值解析器对原始属性值进行一个解析, 获取到一个解析后的属性
// 在这个逻辑中, 内部就调用了 getBean() 这个方法
// 获取当前 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);
}
// 可能转换后的值被存储在合并的bean定义中
// 为了避免对每个创建的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));
}
}
}
// 在 MutablePropertyValues 中设置上 "属性值已经被转换" 的标识
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
// BeanWrapperImpl 继承了 AbstractNestablePropertyAccessor
// 因此它是具备属性处理的功能的
// 实例bean包装类中进行属性值注入
// 参数是通过深拷贝副本创建MutablePropertyValues实例
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
// ...
}
}
上述方法涉及到了几个比较关键的内容:
-
valueResolver.resolveValueIfNecessary(pv, originalValue);通过属性值解析器 BeanDefinitionValueResolver 去解析属性值,若有必要,那么会调用 getBean() 进行底层会依赖 Bean 的创建。
-
convertForProperty(resolvedValue, propertyName, bw, converter);若有必要,会对属性值类型进行转换。
-
bw.setPropertyValues(new MutablePropertyValues(deepCopy));BeanWrapper中设置上属性值,这一步也是我们需要重点关注的。
深入 AbstractPropertyAccessor.setPropertyValues(PropertyValues pvs);
@Override
public void setPropertyValues(PropertyValues pvs) throws BeansException {
// 调用了一个重载方法
setPropertyValues(pvs, false, false);
}
继续深入
@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException {
List<PropertyAccessException> propertyAccessExceptions = null;
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
// 对每个属性值pv键值对进行处理
for (PropertyValue pv : propertyValues) {
try {
// 注入属性
setPropertyValue(pv);
}
// 省略 catch 块
}
// 如果遇到单个异常,则抛出复合异常
if (propertyAccessExceptions != null) {
PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
throw new PropertyBatchUpdateException(paeArray);
}
}
继续深入 AbstractPropertyAccessor.setPropertyValue(pv) :
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
// 通过 PropertyValue 获取到 PropertyTokenHolder 实例
// 正常情况下, 这里一开始是为 null 的
PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
// 对 PropertyTokenHolder 进行一个初始化
if (tokens == null) {
// 获取到属性名称
String propertyName = pv.getName();
//声明一个抽象、可嵌套的属性访问器引用
AbstractNestablePropertyAccessor nestedPa;
try {
// 根据传入的属性名称, 获取到对应的属性访问器
// 这个属性访问器是一个 BeanWrapper 类型的实例
// 这个属性访问器持有者与 bean 相关的各种各样的信息
nestedPa = getPropertyAccessorForPropertyPath(propertyName);
}
catch (NotReadablePropertyException ex) {
// ...
}
// 获取到属性名对应的 PropertyTokenHolder
tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
if (nestedPa == this) {
pv.getOriginalPropertyValue().resolvedTokens = tokens;
}
// 通过属性访问器进行属性的注入
// 我们继续深入到这个方法
nestedPa.setPropertyValue(tokens, pv);
}
else {
// 如果获取到PropertyTokenHolder,那么就直接进行注入
setPropertyValue(tokens, pv);
}
}
深入 AbstractNestablePropertyAccessor.setPropertyValue(tokens, pv); :
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
if (tokens.keys != null) {
processKeyedProperty(tokens, pv);
}
else {
// 处理本地的属性
processLocalProperty(tokens, pv);
}
}
接着深入 AbstractNestablePropertyAccessor.processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv)
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
// 通过传入属性的 actualName 获取到特定的属性处理器
// 我们内部封装了 read、write 方法
// 后续我们会通过 write 方法来实现属性注入(也就是 setter 方法)
// 需要注意的是, 如果我们在 xml 中配置的 propertyName 不等于类中的属性名称
// 那么就会返回一个空值
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
// 如果属性处理器为空, 或者是不可写
if (ph == null || !ph.isWritable()) {
// PropertyValue 是否是可选的, 默认这里为 false
if (pv.isOptional()) {
// 记录日志并返回
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + tokens.actualName +
"' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
}
else {
// 抛出异常
// 这个异常会使用xml中的propertyName以及类中的属性名称进行对比
// 返回一个特定的异常
// 比如 propertyName 为name2, 类中属性名为name
// 那么就会返回 "需要注入的属性名称是否为name"
// 但这种异常要求二者相差不超过两个字符
throw createNotWritablePropertyException(tokens.canonicalName);
}
}
Object oldValue = null;
try {
// 获取到原始属性值
Object originalValue = pv.getValue();
// 用于注入的属性值
Object valueToApply = originalValue;
// 如果 PropertyValue 是有必要转换的
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
// 查看 PropertyValue 是否已经被转换
if (pv.isConverted()) {
// 如果已经被转换, 获取到转换后的的值
valueToApply = pv.getConvertedValue();
} // 若值未被转换, 则会进行相应的处理, 获取到待注入的值
else {
//
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
}
catch (Exception ex) {
//...
}
}
valueToApply = convertForProperty(
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
// 通过属性处理器去注入转换后的值
ph.setValue(valueToApply);
}
// 省略 catch 块
}
继续深入 BeanWrapperImpl.setValue(valueToApply):
@Override
public void setValue(final @Nullable Object value) throws Exception {
// 内部会通过反射机制获取到set方法对应的method对象
final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
this.pd.getWriteMethod());
// 系统安全校验
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(writeMethod);
return null;
});
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
writeMethod.invoke(getWrappedInstance(), value), acc);
}
catch (PrivilegedActionException ex) {
throw ex.getException();
}
} else {
// 通过反射机制突破访问控制符的限制
ReflectionUtils.makeAccessible(writeMethod);
// 执行这个set方法对象的method方法
// 当个逻辑执行结束后, 单个属性的赋值操作就完成了
writeMethod.invoke(getWrappedInstance(), value);
}
}
当上述方法执行完毕后,Bean 实例的属性就已经被成功注入了。
赋值逻辑涉及到的方法调用栈如下图所示:
简单来说,Spring 在赋值逻辑中会完成如下几个工作:
- 所依赖属性的实例创建。
- 所依赖属性的类型转换处理。
- 所依赖属性的校验,比如 xml 中配置的 property 是否与 POJO 类中的属性匹配。
- 获取到 Bean 的 setter 方法, 通过这个方法进行属性注入。
下一章对 Spring 的循环依赖处理机制进行详细分析。