前言

从上一篇文章中得知,在BeanDefinitionValueResolver类的resolveValueIfNecessary方法中,可以解析并且转换参数值的类型。

那么,它到底是怎么做的呢?

1 resolveValueIfNecessary方法

下面重点看看BeanDefinitionValueResolver类的resolveValueIfNecessary方法是如何转换参数值的。

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
  //如果属性值是bean的引用类型
  //<property name="user1" ref="user"/>
  if (value instanceof RuntimeBeanReference) {
      RuntimeBeanReference ref = (RuntimeBeanReference) value;
      //解析相关引用
      return resolveReference(argName, ref);
  }
  //如果属性值是bean名称的引用类型
  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;
  }
  //如果属性值是BeanDefinitionHolder类型
  else if (value instanceof BeanDefinitionHolder) {
      BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
      return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
  }
  //如果属性值是BeanDefinition类型
  else if (value instanceof BeanDefinition) {
      BeanDefinition bd = (BeanDefinition) value;
      String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
              ObjectUtils.getIdentityHexString(bd);
      return resolveInnerBean(argName, innerBeanName, bd);
  }
  //如果属性值是DependencyDescriptor类型
  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) {
      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) {
                  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) {
      return resolveManagedList(argName, (List<?>) value);
  }
  //如果属性值是Set类型
  else if (value instanceof ManagedSet) {
      return resolveManagedSet(argName, (Set<?>) value);
  }
  //如果属性值是Map类型
  else if (value instanceof ManagedMap) {
      return resolveManagedMap(argName, (Map<?, ?>) value);
  }
  //如果属性值是Properies类型
  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;
  }
  //如果是TypedStringValue类型
  else if (value instanceof TypedStringValue) {
      TypedStringValue typedStringValue = (TypedStringValue) value;
      Object valueObject = evaluate(typedStringValue);
      try {
          Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
          if (resolvedTargetType != null) {
              return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
          }
          else {
              return valueObject;
          }
      }
      catch (Throwable ex) {
          throw new BeanCreationException(
                  this.beanDefinition.getResourceDescription(), this.beanName,
                  "Error converting typed String value for " + argName, ex);
      }
  }
  //如果属性值是空bean类型
  else if (value instanceof NullBean) {
      return null;
  }
  else {
      //否则按字符串类型处理
      return evaluate(value);
  }
}

该方法对不同的value类型,使用不同的方法进行解析,主要包含下面这些类型:

  1. RuntimeBeanReference:bean的引用类型。
  2. RuntimeBeanNameReference:bean名称的引用类型。
  3. BeanDefinitionHolder:BeanDefinition持有对象类型。
  4. BeanDefinition:bean的定义对象类型。
  5. DependencyDescriptor:依赖描述类型。
  6. ManagedArray:数组类型。
  7. ManagedList:List集合类型。
  8. ManagedSet:Set集合类型。
  9. ManagedMap:Map集合类型。
  10. ManagedProperties:Properties集合类型。
  11. TypedStringValue:字符串的type和值类型。
  12. NullBean:空bean类型。
  13. String:字符串类型。
  14. String[]:字符串数组类型。
  15. 其他类型。

从上面可以看到对value进行解析的方法有很多,我们挑其中一些比较重要的方法给大家讲解一下。

2 resolveReference方法

对于属性值的解析,要考虑引用类型的情况,在Spring的XML文件中,支持配置这样的参数:

表示user1引用了user,我们获取到的其实是user对应的bean实例。

private Object resolveReference(Object argName, RuntimeBeanReference ref) {
  try {
      Object bean;
      //获取引用bean的类型
      Class<?> beanType = ref.getBeanType();
      //如果引用bean要使用父容器加载
      if (ref.isToParent()) {
          //获取父容器
          BeanFactory parent = this.beanFactory.getParentBeanFactory();
          //如果父容器为空,则抛异常
          if (parent == null) {
              throw new BeanCreationException(
                      this.beanDefinition.getResourceDescription(), this.beanName,
                      "Cannot resolve reference to bean " + ref +
                              " in parent factory: no parent factory available");
          }
          //如果引用bean的类型不为空,则从父容器中beanType获取bean实例
          if (beanType != null) {
              bean = parent.getBean(beanType);
          }
          //否则,从父容器中beanName获取bean实例
          else {
              bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));
          }
      }
      //如果不使用父容器加载
      else {
          String resolvedName;
          //如果引用bean的类型不为空
          if (beanType != null) {
              NamedBeanHolder<?> namedBean = this.beanFactory.resolveNamedBean(beanType);
              bean = namedBean.getBeanInstance();
              resolvedName = namedBean.getBeanName();
          }
          //否则
          else {
              //获取已解析的beanName,主要是有EL表达式的情况
              resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
              //从当前容器中beanName获取bean实例
              bean = this.beanFactory.getBean(resolvedName);
          }
          //将引用的beanName注册到Spring容器中
          this.beanFactory.registerDependentBean(resolvedName, this.beanName);
      }
      //如果从容器中获取了空bean
      if (bean instanceof NullBean) {
          //将bean设置为空
          bean = null;
      }
      //返回bean实例
      return bean;
  }
  catch (BeansException ex) {
      throw new BeanCreationException(
              this.beanDefinition.getResourceDescription(), this.beanName,
              "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
  }
}

下面用一张图总结一下,resolveReference方法的主要流程:

image

当然不同版本的Spring源码,这个流程可能有一点区别。

但是其主要思路是差不多的。

3.resolveInnerBean方法

resolveInnerBean方法主要是为了解析内部bean实例的。

下面用一张图总结一下,resolveInnerBean的主要流程:

image

4.resolveManagedList方法

resolveManagedList方法主要是用来解析List集合的。

这个方法的逻辑非常简单,当遇到List集合时,说白了会遍历集合,获取当中的每一个元素,调用resolveValueIfNecessary方法一个个解析。

想ManagedArray、resolveManagedSet、ManagedMap都是类似的思路,在这里就不过多介绍了。

5. evaluate方法

最后一起看看evaluate方法,它会对字符串或者字符串数组类型的属性值进行解析。

evaluate方法的逻辑是比较简单的,在这里就不画流程图了。

看到这里可能有些小伙伴会问题,为什么字符串类型的属性值,还需要调用doEvaluate方法再去解析一下,到底在解析什么?

下一篇文章会告诉你答案。

最后修改:2026 年 06 月 05 日
如果觉得我的文章对你有用,请随意赞赏