Spring 源码(16)Spring Bean的创建过程(7)属性填充

知识回顾

上一篇介绍了Spring中三级缓存的singletonObjectsearlySingletonObjectssingletonFactoriesSpring在处理循环依赖时在实例化后属性填充前将一个lambda表达式放在了三级缓存中,后续在获取时进行了判断,如果不需要进行对象代理,那么直接返回对象Bean,然后将三级缓存中的对象删除,然后放在二级缓存中,后面在初始化之后又将二级缓存中的对象放在了一级缓存中,然后删除了二级缓存中的对象。

然后介绍了Spring在进行代理对象的创建时,会使用SmartInstantiationBeanPostProcessor接口的getEarlyBeanReference方法进行创建,创建的时候会调用到AbstractAutoProxyCreator类的实现,最终以JDK或者CGLIB的方式进行代理的创建,当然这些细节讲的不是很清晰,只是梳理了大致脉络,后续还会进行较为详细的梳理,敬请期待。

接下来继续主流程的解析,Bean的属性填充。

对象的属性填充

一般来说属性填充,可能会涉及到很多东西,比如填充的属性是基本类型还是引用类型,填充的方式又可以分为按类型、按名称还是其他的,然后填充时值的类型是否需要进行类型转换等。

属性填充:

属性填充大致可以分为对基本类型的数据进行填充和对应用类型的数据填充,populateBean方法中代码比较繁琐,会设计到很多的递归调用,最终解析并填充属性。

Spring中,实际上属性填充大致可以分为四步:

  • 使用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation接口的调用,可以给机会在属性填充前对Bean进行修改,并且可以定制字段的填充
  • 按照注入方式进行属性的填充,最终会将解析到的属性和引用放入PropertyValues
    • 按类型进行自动注入
    • 按名称进行自动注入
  • 如果存在InstantiationAwareBeanPostProcessor接口,那么循环去调用postProcessProperties这个方法进行注解的注入,这里调用的实际上就是前面进行Bean的合并时解析的注解,比如:@Autowired@Resource@Value
  • 属性值的处理和解析
    • 创建一个BeanDefinitionValueResolver 值解析器
    • 循环去遍历解析属性值,解析过程中会用到类型转换的转换服务ConversionServiceSPEL表达式的解析、属性编辑器PropertyEditor
    • 最终解析完,会调用到属性的set方法进行写入

这里贴一下属性值解析的时候的源码:

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {   // We must check each value to see whether it requires a runtime reference   // to another bean to be resolved.   // 根据值对象的类型进行解析   if (value instanceof RuntimeBeanReference) {    // 运行时引用    RuntimeBeanReference ref = (RuntimeBeanReference) value;    return resolveReference(argName, ref);   }   else if (value instanceof RuntimeBeanNameReference) {    String refName = ((RuntimeBeanNameReference) value).getBeanName();    refName = String.valueOf(doEvaluate(refName));    if (!this.beanFactory.containsBean(refName)) {     throw new BeanDefinitionStoreException(       "Invalid bean name '" + refName + "' in bean reference for " + argName);    }    return refName;   }   else if (value instanceof BeanDefinitionHolder) {    // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.    BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;    return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());   }   else if (value instanceof BeanDefinition) {    // Resolve plain BeanDefinition, without contained name: use dummy name.    BeanDefinition bd = (BeanDefinition) value;    String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +      ObjectUtils.getIdentityHexString(bd);    return resolveInnerBean(argName, innerBeanName, bd);   }   else if (value instanceof DependencyDescriptor) {    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);    Object result = this.beanFactory.resolveDependency(      (DependencyDescriptor) value, this.beanName, autowiredBeanNames, this.typeConverter);    for (String autowiredBeanName : autowiredBeanNames) {     if (this.beanFactory.containsBean(autowiredBeanName)) {      this.beanFactory.registerDependentBean(autowiredBeanName, this.beanName);     }    }    return result;   }   // 如果值是数组   else if (value instanceof ManagedArray) {    // May need to resolve contained runtime references.    ManagedArray array = (ManagedArray) value;    Class<?> elementType = array.resolvedElementType;    if (elementType == null) {     String elementTypeName = array.getElementTypeName();     if (StringUtils.hasText(elementTypeName)) {      try {       elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());       array.resolvedElementType = elementType;      }      catch (Throwable ex) {       // Improve the message by showing the context.       throw new BeanCreationException(         this.beanDefinition.getResourceDescription(), this.beanName,         "Error resolving array type for " + argName, ex);      }     }     else {      elementType = Object.class;     }    }    return resolveManagedArray(argName, (List<?>) value, elementType);   }   // 如果值是list   else if (value instanceof ManagedList) {    // May need to resolve contained runtime references.    return resolveManagedList(argName, (List<?>) value);   }   // 如果值是set   else if (value instanceof ManagedSet) {    // May need to resolve contained runtime references.    return resolveManagedSet(argName, (Set<?>) value);   }   // 如果值是map   else if (value instanceof ManagedMap) {    // May need to resolve contained runtime references.    return resolveManagedMap(argName, (Map<?, ?>) value);   }   // 如果值是properties   else if (value instanceof ManagedProperties) {    Properties original = (Properties) value;    Properties copy = new Properties();    original.forEach((propKey, propValue) -> {     if (propKey instanceof TypedStringValue) {      propKey = evaluate((TypedStringValue) propKey);     }     if (propValue instanceof TypedStringValue) {      propValue = evaluate((TypedStringValue) propValue);     }     if (propKey == null || propValue == null) {      throw new BeanCreationException(        this.beanDefinition.getResourceDescription(), this.beanName,        "Error converting Properties key/value pair for " + argName + ": resolved to null");     }     copy.put(propKey, propValue);    });    return copy;   }   // 如果值是字符串   else if (value instanceof TypedStringValue) {    // Convert value to target type here.    TypedStringValue typedStringValue = (TypedStringValue) value;    // 校验值,比如说使用spel表达式进行解析,然后得到这个值    Object valueObject = evaluate(typedStringValue);    try {     Class<?> resolvedTargetType = resolveTargetType(typedStringValue);     if (resolvedTargetType != null) {      // 类型转换      return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);     }     else {      return valueObject;     }    }    catch (Throwable ex) {     // Improve the message by showing the context.     throw new BeanCreationException(       this.beanDefinition.getResourceDescription(), this.beanName,       "Error converting typed String value for " + argName, ex);    }   }   else if (value instanceof NullBean) {    return null;   }   else {    return evaluate(value);   }  } 

代码比较长,大致的话就是对属性进行分类处理,比如引用类型的,ListMapSetProperties、数组、String类型的等。

如果在填充的过程中,发现需要的Bean不存在,那么又会进行getBeandoGetBeancreateBeandoCreateBean的调用,然后递归的入栈出栈调用,最终完成属性的填充。

下篇继续主流程中的Bean的初始化initializeBean调用的解读。

商匡云商
Logo
注册新帐户
对比商品
  • 合计 (0)
对比
0
购物车