【超详细的Spring源码分析 —— 05 Spring IoC 对于 Bean 管理的核心组件分析 - Bean 的属性注入】

413 阅读8分钟

首先我们要明确,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) {
    	// ...
    }
}

上述方法涉及到了几个比较关键的内容:

  1. valueResolver.resolveValueIfNecessary(pv, originalValue);

    通过属性值解析器 BeanDefinitionValueResolver 去解析属性值,若有必要,那么会调用 getBean() 进行底层会依赖 Bean 的创建。

  2. convertForProperty(resolvedValue, propertyName, bw, converter);

    若有必要,会对属性值类型进行转换。

  3. 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 在赋值逻辑中会完成如下几个工作:

  1. 所依赖属性的实例创建。
  2. 所依赖属性的类型转换处理。
  3. 所依赖属性的校验,比如 xml 中配置的 property 是否与 POJO 类中的属性匹配。
  4. 获取到 Bean 的 setter 方法, 通过这个方法进行属性注入。

下一章对 Spring 的循环依赖处理机制进行详细分析。