Spring 属性填充(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析DNS,个人版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring 的属性填充主要是在 Bean 被创建后,通过 populateBean 方法来完成对象属性赋值以逐步完成 Bean 的初始化工作。

我们再来到 doResolveDependency 方法


public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
                  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
  try {
    // 如果 DependencyDescriptor 是一个 ShortcutDependencyDescriptor
    // 那么会直接理解 beanName 从 beanFactory 中拿到一个 bean
    // 在利用 @Autowired 注解来进行依赖注入时会利用 ShortcutDependencyDescriptor 来进行依赖注入的缓存
    // 表示当解析完成某个依赖信息后,会把依赖的 bean 的 beanName 缓存起来
    Object shortcut = descriptor.resolveShortcut(this);
    if (shortcut != null) {
      return shortcut;
    }
    // 获取 descriptor 的具体赖姓
    Class<?> type = descriptor.getDependencyType();
    // 1. 获取 @Value 注解中所配置的值
    Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); //判断是否通过 @Value 指定了
    if (value != null) {
      if (value instanceof String) {
        // 先进行占位符的填充,解析 "$" 符号
        String strVal = resolveEmbeddedValue((String) value);
        BeanDefinition bd = (beanName != null && containsBean(beanName) ?
            getMergedBeanDefinition(beanName) : null);
        // 解析 Spring EL 表达式, 解析 "#" 符号(可以是运算,也可以是某个 bean 的名字)
        value = evaluateBeanDefinitionString(strVal, bd);
      }
      TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
      try {
        return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
      } catch (UnsupportedOperationException ex) {
        // A custom TypeConverter which does not support TypeDescriptor resolution...
        return (descriptor.getField() != null ?
            converter.convertIfNecessary(value, type, descriptor.getField()) :
            converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
      }
    }
    //没有使用 @Value 注解
    //2. 要注入的类型不是一个 Map,Array, Collection
    Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
    if (multipleBeans != null) {
      return multipleBeans;
    }
    //通过 Type 查找,可能找到多个, 这里的 value ,可能是具体的实例对象, 也能暂时只是 Class 对象
    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    if (matchingBeans.isEmpty()) {
      if (isRequired(descriptor)) {
        raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
      }
      return null;
    }
    String autowiredBeanName;
    Object instanceCandidate;
    // 根据 type 查找到了多个
    if (matchingBeans.size() > 1) {
      // 如果找到了多个,去尝试确定出唯一的一个
      autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
      if (autowiredBeanName == null) {
        if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
          //如果找到多个,并且依赖是 required , 或者不是数组或者 Collection 或者 Map
          return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
        } else {
          // In case of an optional Collection/Map, silently ignore a non-unique case:
          // possibly it was meant to be an empty collection of multiple regular beans
          // (before 4.3 in particular when we didn't even look for collection beans).
          return null;
        }
      }
      instanceCandidate = matchingBeans.get(autowiredBeanName);
    } else {
      // We have exactly one match.
      Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
      autowiredBeanName = entry.getKey();
      instanceCandidate = entry.getValue();
    }
    if (autowiredBeanNames != null) {
      autowiredBeanNames.add(autowiredBeanName);
    }
    if (instanceCandidate instanceof Class) {
      // 调用 beanFactory.getbean() 创建 bean 对象
      instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
    }
    Object result = instanceCandidate;
    if (result instanceof NullBean) {
      if (isRequired(descriptor)) {
        raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
      }
      result = null;
    }
    if (!ClassUtils.isAssignableValue(type, result)) {
      throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
    }
    return result;
  } finally {
    ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
  }
}


上面有我们的常用注入 @Value, @Autowired 的处理,当我们同一个类型的 Bean 查找到多个结果的时候,我们来看如何选择的 determineAutowireCandidate 方法的实现。


protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
    Class<?> requiredType = descriptor.getDependencyType();
    // 取 @Primary 的 bean
    String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
    if (primaryCandidate != null) {
      return primaryCandidate;
    }
    // 取优先级最高的 Bean 通过 @Priority 来定义优先级,数字越小,优先级越高
    String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
    if (priorityCandidate != null) {
      return priorityCandidate;
    }
    // Fallback
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
      String candidateName = entry.getKey();
      Object beanInstance = entry.getValue();
      if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
          // 根据属性名确定
          matchesBeanName(candidateName, descriptor.getDependencyName())) {
        return candidateName;
      }
    }
    return null;
  }


doResolveDependency 总结


(1) 首先调用 DefaultListableBeanFactory#doResolveDependency 方法中通过属性来获取对应的需要注入的 Bean 。


(2) 第一步解析 @Value 注解, 如果存在就解析 el 表达式获取 Bean 。


(3)  第二步解析 @Autowired 自动注入注解,如果存在首先就去解析这个注解。

(4) 通过依赖的类型去查找所有符合条件的候选 Bean。


(5)  当符合条件的 Bean 的个数为 0 的时候,判断 @Autowired 的 required 属性是否为 true, 如果是 true  那么就抛异常,提示找不到 Bean。


(6) 如果匹配到1个的时候,我们就直接使用。


(7) 如果匹配到多个的时候, 我们就需要做一下的选择:


首先遍历所有的候选 beanName, 判断是否有 @Primary 注解,如果有一个就返回,如果有多个会抛出异常 NoUniqueBeanDefinitionException

然后,遍历所有的候选 beanName, 判断是否有 @Priority 注解,如果有就按照自然顺序排序返回第一个,如果存在多个 Bean 优先级相同则抛出异常 NoUniqueBeanDefinitionException( 注意:这里容易混淆 @Order 注解);

最后,遍历所有的候选 beanName,如果上述两种情况都不能选择到匹配的,那么将读取参数名通过 byName 的方式来匹配 Bean。


(8)  把所有的字段和需要注入的到 Bean 的属性之后完成属性的注入。


(9) 最后,若存在属性pvs,那就做赋值操作


applyPropertyValues


该方法主要是实现 pvs 的值的运用


(1) 检测属性值列表是否已转换过的,若转换过,则直接填充属性,无需再次转换

(2) 遍历属性值列表 pvs,解析原始值 originalValue,得到解析值 resolvedValue


(3) 对解析后的属性值 resolvedValue 进行类型转换


(4) 将类型转换后的属性值设置到 PropertyValue 对象中,并将 PropertyValue 对象存入 deepCopy 集合中将 deepCopy 中的属性信息注入到 bean 对象中


// 本方法传入了beanName和bean定义信息,以及它对应的BeanWrapper和value值
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;
  // 判断是否是 类型 MutablePropertyValues
  if (pvs instanceof MutablePropertyValues) {
    mpvs = (MutablePropertyValues) pvs;
    // 若该mpvs中的所有属性值都已经转换为对应的类型,则把mpvs设置到BeanWrapper中,返回
    if (mpvs.isConverted()) {
      // Shortcut: use the pre-converted values as-is.
      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());
  }
  // 若调用者没有自定义转换器,那就使用BeanWrapper本身(因为BeanWrapper实现了TypeConverter 接口)
  TypeConverter converter = getCustomTypeConverter();
  if (converter == null) {
    converter = bw;
  }
  // 获取BeanDefinitionValueResolver,该Bean用于将bean定义对象中包含的值解析为应用于目标bean实例的实际值。
  BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
  // Create a deep copy, resolving any references for values.
  List<PropertyValue> deepCopy = new ArrayList<>(original.size());
  boolean resolveNecessary = false;
  // 遍历没有被解析的original属性值
  for (PropertyValue pv : original) {
    if (pv.isConverted()) {
      deepCopy.add(pv);
    }
    else {// 被解析过的PropertyValue此处会一步步解析
      String propertyName = pv.getName();
      Object originalValue = pv.getValue();
      // 解析各式各样的值
      Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
      Object convertedValue = resolvedValue;
      // 属性可写 并且 不是嵌套(如foo.bar,java中用getFoo().getBar()表示)或者索引(如person.addresses[0])属性
      boolean convertible = bw.isWritableProperty(propertyName) &&
          !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
      if (convertible) {
        // 用类型转换器进行转换
        convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
      }
      // Possibly store converted value in merged bean definition,
      // in order to avoid re-conversion for every created bean instance.
      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));
      }
    }
  }
  // 标记mpvs已经转换
  if (mpvs != null && !resolveNecessary) {
    mpvs.setConverted();
  }
  // Set our (possibly massaged) deep copy.
  // 使用转换后的值进行填充
  try {
    // 对属性的值进行注入
    bw.setPropertyValues(new MutablePropertyValues(deepCopy));
  }
  catch (BeansException ex) {
    throw new BeanCreationException(
        mbd.getResourceDescription(), beanName, "Error setting property values", ex);
  }
}


Spring 源码解析











相关文章
|
2月前
|
存储 Java 数据安全/隐私保护
|
28天前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
28 0
|
1月前
|
运维 Java 测试技术
Spring运维之boo项目表现层测试加载测试的专用配置属性以及在JUnit中启动web服务器发送虚拟请求
Spring运维之boo项目表现层测试加载测试的专用配置属性以及在JUnit中启动web服务器发送虚拟请求
24 3
|
1月前
|
运维 Java 关系型数据库
Spring运维之boot项目bean属性的绑定读取与校验
Spring运维之boot项目bean属性的绑定读取与校验
30 2
|
1月前
|
XML 运维 Java
Spring运维之boot项目打包jar和插件运行并且设置启动时临时属性和自定义配置文件
Spring运维之boot项目打包jar和插件运行并且设置启动时临时属性和自定义配置文件
26 1
|
2月前
|
XML Java 数据格式
Spring 属性注入方式
Spring 属性注入方式
25 2
|
2月前
|
Java 数据库连接 数据库
Spring事务简介,事务角色,事务属性
Spring事务简介,事务角色,事务属性
29 2
|
2月前
|
Java Apache Spring
Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求
【5月更文挑战第4天】Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求;Cglib BeanCopier用于转换为Cglib代理对象;Apache PropertyUtils处理属性操作;Dozer支持复杂对象映射。选择工具取决于具体需求,如需精细控制或对象映射,推荐Dozer或Apache PropertyUtils。Apache BeanUtils可能因潜在的封装性破坏被禁用。
37 3
|
2月前
|
Java 开发者 Spring
Spring Boot中的资源文件属性配置
【4月更文挑战第28天】在Spring Boot应用程序中,配置文件是管理应用程序行为的重要组成部分。资源文件属性配置允许开发者在不重新编译代码的情况下,对应用程序进行灵活地配置和调整。本篇博客将介绍Spring Boot中资源文件属性配置的基本概念,并通过实际示例展示如何利用这一功能。
36 1
|
2月前
|
JSON Java 数据库连接
属性注入掌握:Spring Boot配置属性的高级技巧与最佳实践
属性注入掌握:Spring Boot配置属性的高级技巧与最佳实践
44 1