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

343 阅读10分钟

首先我们要明确,Spring 在创建一个 bean 实例时,会先创建一个属性值为 null 的实例,然后再进行一个赋值。在上一篇中已经对创建实例的流程进行了一个详细的分析,在这一章中我们继续来看属性注入这一块的内容。

首先,我们先以一个宏观的角度来了解属性注入,我们在 pojo 类中的 set 方法中添加一些 print 的逻辑:

public class Student {
    private String name;
    private int age;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        System.out.println("set name method");
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        System.out.println("set age method");
        this.age = age;
    }
}

然后通过容器获取到 bean:

Student student = defaultListableBeanFactory.getBean("student", Student.class);

看一下控制台中的打印信息:

set name method
set age method

能够发现,pojo 类中的 set 方法是会被执行的。

其实通过我们之前分析的一些 Spring 的解析、加载bean的机制,也能够大致地猜出属性注入的一个大概方式:

  1. 首先,Spring 一定会根据 BeanDefinitionHolder 进行 bean 的初始化,而这个 BeanDefinitionHolder 就包含了我们在 xml 配置文件中配置的属性、类加载器、全限定类名等信息。
  2. 其次,Spring 在初始化时一定会通过反射获取到 BeanDefinition 对应的构造方法,然后通过构造方法去执行 bean 初始化。

那么同样地,我们也能够通过反射获取到 BeanDefinition 对应的 set 方法,然后进行一个赋值的动作。

一、bean的属性注入详解

首先我们去到创建实例 bean 的那个函数:

AbstractAutowireCapableBeanFactory.doCreateBean()

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
    
    // 省略掉前面的逻辑, 我们只关注属性注入
    
    // 获取到刚被初始化的Bean实例
    Object exposedObject = bean;
    try {
        // 这个方法中, 就封装了注入属性的一个逻辑
    	populateBean(beanName, mbd, instanceWrapper);
    	
    	// 初始化给定的bean实例
    	exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
    	// 省略异常逻辑
    }
    
    if (earlySingletonExposure) {
    	//... 省略这部分的逻辑
    }
    
    // 注册bean销毁时的一些逻辑
    try {
    	registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
    	// ...
    }
    return exposedObject;
}

进入到 populateBean():

AbstractAutowireCapableBeanFactory.populateBean()

这个方法的参数有 beanName、RootBeanDefinition、BeanWrapper。要做的事情就显而易见了:把 bean 定义中解析出来的属性值注入到 bean实例包装类里封装的 bean 实例上。

我们只对关键的代码进行分析:

@SuppressWarnings("deprecation")  // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 实例包装类的非空判断
    if (bw == null) {
    	// ...
    }
    
    // 前置处理(如果需要的话)
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    	// ...
    }
    
    // 这里就比较关键, 会获取到 beanDefinition 中的属性值列表
    // 用了一个三目表达式, 先校验是否有属性值, 有就返回封装了属性值的对象, 没有就返回null
    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);
    }
}

在上述方法中,我们已经成功获取到了属性列表,然后继续执行后续的注入逻辑,深入到 applyPropertyValues():

AbstractAutowireCapableBeanFactory.applyPropertyValues(beanName, mbd, bw, 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());
    }
    
    // 尝试获取自定义的类型转换器, 默认为 null
    TypeConverter converter = getCustomTypeConverter();
    // 若未成功获取到, 就将 BeanWrapper 实例赋值给类型转换器的引用
    if (converter == null) {
    	converter = bw;
    }
    
    // 创建出BeanDefinition的属性值解析器
    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);
            }
            
            // 通过属性值解析器对原始属性值进行一个解析, 获取到一个解析后的属性
            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 {
        // 实例bean包装类中进行一个属性值注入
        // 深入这个方法
    	bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    }
    catch (BeansException ex) {
    	// ...
    }
}

上述方法中主要完成了属性值的转换逻辑,但还并未对属性值进行注入,我们继续深入到 AbstractPropertyAccessor.setPropertyValues(new MutablePropertyValues(deepCopy)); 这个逻辑:

AbstractPropertyAccessor 是 BeanWrapperImpl 的父抽象类:

@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);
    }
}

上述方法会遍历每一个属性列表,然后调用 setPropertyValue()

继续深入 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) {
    // 获取到属性处理器(也就是针对特定属性的一个处理器)
    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 {
            // 抛出异常
            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);
    }
}

上述方法会通过反射机制获取到属性值对应的 set 方法,然后将属性值 value 注入到 BeanWrapper 包装的实例中。

二、总结

总的来说,赋值的步骤可以概括为如下几个:

  1. 通过 BeanDefinition 获取到属性列表 PropertyValues。
  2. 将 PropertyValues 向下类型转换为 MutablePropertyValues,表示可变的属性列表,它内部封装了原始属性值以及类型转换的属性值。
  3. 紧接着通过深拷贝的方式(用 ArrayList 存储转换后的属性实体 PropertyValue,然后将这个 ArrayList 作为参数构建一个新的 MutablePropertyValues),将 MutablePropertyValues 中需要转换的属性值转换为相应类型的属性值。
  4. 将新创建的 MutablePropertyValues 作为参数,调用 BeanWrapper 的 setPropertyValues() 方法。
  5. 遍历 MutablePropertyValues,处理每一个 PropertyValue 实体,进行属性注入。
  6. 通过属性名称获取到对应的属性访问器 AbstractNestablePropertyAccessor,通过属性访问器进行属性注入
  7. 通过属性访问器中封装的 actualName(真实的属性名称),获取到对应的属性处理器。
  8. 通过属性访问器,对值进行注入。
  9. 通过反射机制获取到对应属性的 set 方法对象,调用 set 方法完成属性赋值。

以上就是整个属性注入的大概流程。从第一篇到第七篇,整个 IoC 的流程就大概分析完了,但中间我跳过了一些 AOP 相关的内容没有分析。

AOP 的实现是基于 IoC 的,因此我们得先对 IoC 有一个全面的了解才能分析 AOP,在后续的内容中我将对 AOP 进行详细的分析。