Spring源码阅读:默认标签的解析

上一篇文章提到过Spring中的标签包括默认标签自定义标签,而两种标签的用法以及解析方式存在着很大的不同,先说说默认标签的解析。

首先我们需要明确两个概念:属性子元素

  • 属性是指一个bean标签它自带的一些属性,例如idnameparent等,都存放于AbstractBeanDefinition的各项成员变量中。
  • 子元素是指bean标签下的一些子标签的内容,例如:
<bean id="mybbTestBean" class="bean.MyTestBean">
	<meta key="testStr" value="aaaa"/>
</bean>

其中的meta就是一个子元素。

默认标签的解析是在parseDefaultElement函数中进行的,分别对importaliasbeanbeans做了不同的处理。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

1 bean标签的解析和注册

进入processBeanDefinition(ele, delegate)方法:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

大致逻辑如下:

  1. 委托BeanDefinitionParserDelegateparseBeanDefinitionElement方法进行元素解析,返回bhHolder。这个bdHolder实例已经包含我们配置文件中配置的各种属性了,例如classnameidalias等。
  2. 当返回的bdHolder不为空的情况下,若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析。
  3. 解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtilsregisterBeanDefinition方法。
  4. 最后发出响应事件,通知相关的监听器,这个bean就加载完成了。

1.1 解析BeanDefinition

我们进入到BeanDefinitionDelegate类的parseBeanDefinitionElement方法。

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
  return parseBeanDefinitionElement(ele, null);
}

/**
	 * Parses the supplied {@code <bean>} element. May return {@code null}
	 * if there were errors during parse. Errors are reported to the
	 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
	 */
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
  // 解析id属性
  String id = ele.getAttribute(ID_ATTRIBUTE);
  // 解析name属性
  String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

  List<String> aliases = new ArrayList<>();
  if (StringUtils.hasLength(nameAttr)) {
    // name属性也是alias的一种
    String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    aliases.addAll(Arrays.asList(nameArr));
  }

  String beanName = id;
  if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    beanName = aliases.remove(0);
    if (logger.isTraceEnabled()) {
      logger.trace("No XML 'id' specified - using '" + beanName +
                   "' as bean name and " + aliases + " as aliases");
    }
  }

  if (containingBean == null) {
    checkNameUniqueness(beanName, aliases, ele);
  }

  // 对标签其他属性进行解析,如class、parent等
  AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
  if (beanDefinition != null) {
    if (!StringUtils.hasText(beanName)) {
      try {
        // 如果不存在beanName那么根据Spring提供的命名规则为当前bean生成
        if (containingBean != null) {
          beanName = BeanDefinitionReaderUtils.generateBeanName(
            beanDefinition, this.readerContext.getRegistry(), true);
        }
        else {
          beanName = this.readerContext.generateBeanName(beanDefinition);
          // Register an alias for the plain bean class name, if still possible,
          // if the generator returned the class name plus a suffix.
          // This is expected for Spring 1.2/2.0 backwards compatibility.
          String beanClassName = beanDefinition.getBeanClassName();
          if (beanClassName != null &&
              beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
              !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
            aliases.add(beanClassName);
          }
        }
        if (logger.isTraceEnabled()) {
          logger.trace("Neither XML 'id' nor 'name' specified - " +
                       "using generated bean name [" + beanName + "]");
        }
      }
      catch (Exception ex) {
        error(ex.getMessage(), ele);
        return null;
      }
    }
    String[] aliasesArray = StringUtils.toStringArray(aliases);
    // 封装进BeanDefinitionHolder中
    return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
  }

  return null;
}

parseBeanDefinitionElement的主要工作包括如下内容:

  1. 提取元素中的id以及name属性。
  2. 进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例中。
  3. 如果检测到bean没有指定beanName,就用默认规则为此bean生成beanName
  4. 将获取到的信息封装到BeanDefinitionHolder的实例中。

进一步查看步骤2中对标签其他属性的解析过程。

@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
  Element ele, String beanName, @Nullable BeanDefinition containingBean) {

  this.parseState.push(new BeanEntry(beanName));

  String className = null;
  if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
    // 解析class属性
    className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
  }
  String parent = null;
  if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
    // 解析parent属性
    parent = ele.getAttribute(PARENT_ATTRIBUTE);
  }

  try {
    // 创建用于承载属性的AbstractBeanDefinition
    AbstractBeanDefinition bd = createBeanDefinition(className, parent);

    // 解析默认bean的各种属性
    parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

    // 解析元数据
    parseMetaElements(ele, bd);
    // 解析lookup-method属性
    parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
    // 解析replaced-method属性
    parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

    // 解析构造函数参数
    parseConstructorArgElements(ele, bd);
    // 解析property子元素
    parsePropertyElements(ele, bd);
    // 解析qualifier子元素
    parseQualifierElements(ele, bd);

    bd.setResource(this.readerContext.getResource());
    bd.setSource(extractSource(ele));

    return bd;
  }
  catch (ClassNotFoundException ex) {
    error("Bean class [" + className + "] not found", ele, ex);
  }
  catch (NoClassDefFoundError err) {
    error("Class that bean class [" + className + "] depends on not found", ele, err);
  }
  catch (Throwable ex) {
    error("Unexpected failure during bean definition parsing", ele, ex);
  }
  finally {
    this.parseState.pop();
  }

  return null;
}

1.1.1 解析子元素constructor-arg

举个Spring构造函数配置的例子:

<bean id="helloBean" class="com.HelloBean">
  <constructor-arg index="0">
    <value>mutianjie</value>
  </constructor-arg>
  <constructor-arg index="1">
  	<value>你好</value>
  </constructor-arg>
</bean>

上面的配置实现的功能是对HelloBean自动寻找对应的构造函数,并在初始化的时候将设置的参数传入进去。对于constructor-arg子元素的解析,Spring是通过parseConstructorArgElements函数来实现的,具体代码如下:

	/**
	 * Parse constructor-arg sub-elements of the given bean element.
	 */
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
  NodeList nl = beanEle.getChildNodes();
  for (int i = 0; i < nl.getLength(); i++) {
    Node node = nl.item(i);
    if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
      parseConstructorArgElement((Element) node, bd);
    }
  }
}

在循环中,parseConstructorArgElements函数遍历了所有的<constructor-arg>标签,提取所有的子元素。具体的解析放在了另一个函数parseConstructorArgElement中,该函数的具体代码如下:

/**
	 * Parse a constructor-arg element.
	 */
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
  // 提取index属性
  String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
  // 提取type属性
  String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
  // 提取name属性
  String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
  if (StringUtils.hasLength(indexAttr)) {
    try {
      int index = Integer.parseInt(indexAttr);
      if (index < 0) {
        error("'index' cannot be lower than 0", ele);
      }
      else {
        try {
          this.parseState.push(new ConstructorArgumentEntry(index));
          // 解析ele对应的属性元素
          Object value = parsePropertyValue(ele, bd, null);
          // 封装解析出来的元素
          ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
          if (StringUtils.hasLength(typeAttr)) {
            valueHolder.setType(typeAttr);
          }
          if (StringUtils.hasLength(nameAttr)) {
            valueHolder.setName(nameAttr);
          }
          valueHolder.setSource(extractSource(ele));
          if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
            // 不允许重复指定相同的参数
            error("Ambiguous constructor-arg entries for index " + index, ele);
          }
          else {
            bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
          }
        }
        finally {
          this.parseState.pop();
        }
      }
    }
    catch (NumberFormatException ex) {
      error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
    }
  }
  else {
    // 没有index属性则自动寻找
    try {
      this.parseState.push(new ConstructorArgumentEntry());
      Object value = parsePropertyValue(ele, bd, null);
      ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
      if (StringUtils.hasLength(typeAttr)) {
        valueHolder.setType(typeAttr);
      }
      if (StringUtils.hasLength(nameAttr)) {
        valueHolder.setName(nameAttr);
      }
      valueHolder.setSource(extractSource(ele));
      bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
    }
    finally {
      this.parseState.pop();
    }
  }
}

根据以上代码总结出来的流程为:

如果配置中指定了index属性,那么操作步骤如下:

  1. 使用parsePropertyValue方法解析constructor-arg的子元素
  2. 使用ConstructArgumentValues.ValueHolder类型来封装解析出来的元素
  3. typenameindex属性一并封装在ConstructArgumentValues.ValueHolder中,并添加至当前BeanDefinitionconstructorArgumentValuesindexedArgumentValue中。

如果配置中未指定index属性,前两步操作与指定index属性的做法相同,但是第三步中,valueHolder会添加至当前BeanDefinitionconstructorArgumentValuesgenericArgumentValue中。

在构造函数解析中,解析constructor-arg的子元素使用的是parsePropertyValue方法,它是用来解析某一个具体的构造函数参数的。这个方法的代码如下:

@Nullable
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
  String elementName = (propertyName != null ?
                        "<property> element for property '" + propertyName + "'" :
                        "<constructor-arg> element");

  // 一个属性只能对应一种类型,如 ref, value, list等
  NodeList nl = ele.getChildNodes();
  Element subElement = null;
  for (int i = 0; i < nl.getLength(); i++) {
    Node node = nl.item(i);
    if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
        !nodeNameEquals(node, META_ELEMENT)) {
      // Child element is what we're looking for.
      if (subElement != null) {
        error(elementName + " must not contain more than one sub-element", ele);
      }
      else {
        subElement = (Element) node;
      }
    }
  }

  // 解析constructor-arg的ref属性
  boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
  // 解析constructor-arg的value属性
  boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
  if ((hasRefAttribute && hasValueAttribute) ||
      ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
    error(elementName +
          " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
  }

  if (hasRefAttribute) {
    // ref属性的处理,使用RuntimeBeanReference封装对应的ref名称
    String refName = ele.getAttribute(REF_ATTRIBUTE);
    if (!StringUtils.hasText(refName)) {
      error(elementName + " contains empty 'ref' attribute", ele);
    }
    RuntimeBeanReference ref = new RuntimeBeanReference(refName);
    ref.setSource(extractSource(ele));
    return ref;
  }
  else if (hasValueAttribute) {
    // value属性的处理,使用TypedStringValue封装
    TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
    valueHolder.setSource(extractSource(ele));
    return valueHolder;
  }
  else if (subElement != null) {
    // map、list等子元素的处理,如
    /**
      * <constructor-arg>
      * <map>
      * 	<entry key="key" value="value"/>
      * </map>
      * </constructor-arg>
      */
    return parsePropertySubElement(subElement, bd);
  }
  else {
    // Neither child element nor "ref" or "value" attribute found.
    error(elementName + " must specify a ref or value", ele);
    return null;
  }
}

值得注意的是,除了refvalue两种子元素之外,还有嵌套子元素如maplistarray等。这类嵌套子元素的处理在parsePropertySubElement方法中完成,对嵌套子元素进行分类处理。

1.1.2 解析子元素property

parsePropertyElements函数完成了对property属性的提取。property使用方式如下:

<bean id="test" class="test.TestClass">
	<property name="testStr" value="aaa"/>
</bean>
<!--或者-->
<bean id="a">
	<property name="p">
  	<list>
    	<value>aa</value>
      <value>bb</value>
    </list>
  </property>
</bean>

而具体的解析过程与前面的子元素一样,也是使用单数形式的方法parsePropertyElement来对所有的property子元素进行解析,代码如下:

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
  NodeList nl = beanEle.getChildNodes();
  for (int i = 0; i < nl.getLength(); i++) {
    Node node = nl.item(i);
    if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
      parsePropertyElement((Element) node, bd);
    }
  }
}

parsePropertyElement方法的实现如下:

public void parsePropertyElement(Element ele, BeanDefinition bd) {
  String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
  if (!StringUtils.hasLength(propertyName)) {
    error("Tag 'property' must have a 'name' attribute", ele);
    return;
  }
  this.parseState.push(new PropertyEntry(propertyName));
  try {
    if (bd.getPropertyValues().contains(propertyName)) {
      error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
      return;
    }
    Object val = parsePropertyValue(ele, bd, propertyName);
    PropertyValue pv = new PropertyValue(propertyName, val);
    parseMetaElements(ele, pv);
    pv.setSource(extractSource(ele));
    bd.getPropertyValues().addPropertyValue(pv);
  }
  finally {
    this.parseState.pop();
  }
}

可以看到上面函数与构造函数注入方式不同的是将返回值使用PropertyValue封装,并记录在BeanDefinition中的propertyValues属性中。

1.2 AbstractBeanDefinition属性

至此我们便完成了对XML文档到GenericBeanDefinition的转换,也就是说,所有的配置都可以在GenericBeanDefinition中找到对应的配置。

1.3 解析默认标签中的自定义标签元素

我们来回顾一下默认标签解析函数的起始函数:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  if (bdHolder != null) {
    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    try {
      // Register the final decorated instance.
      BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    }
    catch (BeanDefinitionStoreException ex) {
      getReaderContext().error("Failed to register bean definition with name '" +
                               bdHolder.getBeanName() + "'", ele, ex);
    }
    // Send registration event.
    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  }
}

我们已经用大量篇幅分析了BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele)这句代码。接下来,我们进入到下一行代码delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)中。

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
   return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}

这段代码的作用是对beanDefinition进行装饰,当Spring中的bean使用的是默认的标签配置,但是其中子元素使用了自定义的配置时,这句代码就会起作用,如:

<bean id="test" class="test.MyClass">
	<mybean:user username="aaa"/>
</bean>

这并不是自定义标签类型的解析,因为它并不是以bean的形式而是以自定义属性的形式出现的。decorateBeanDefinitionIfRequired方法实现了寻找自定义标签并根据自定义标签寻找命名空间处理器,并进行进一步的解析。

1.4 注册解析的BeanDefinition

接下来还剩下的工作是对BeanDefinition的注册,也就是BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())方法的实现。

public static void registerBeanDefinition(
  BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
  throws BeanDefinitionStoreException {

  // 使用beanName作为唯一标识注册
  String beanName = definitionHolder.getBeanName();
  registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

  // 注册所有的别名
  String[] aliases = definitionHolder.getAliases();
  if (aliases != null) {
    for (String alias : aliases) {
      registry.registerAlias(beanName, alias);
    }
  }
}

可以看到,对BeanDefinition的注册分为两部分:通过beanName和别名进行注册。

1.4.1 通过beanName注册BeanDefinition

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         /**
          * 注册前的最后一次校验,这里的校验不同于之前的XML文件校验
          * 主要是对与AbstractBeanDefinition属性中的methodOverrides校验
          * 校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法根本不存在
          */
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   // 这里使用ConcurrentHashMap进行并发访问全局变量beanDefinitionMap
   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   if (existingDefinition != null) {
      //  处理注册已经注册的beanName情况
      if (!isAllowBeanDefinitionOverriding()) {
         // 如果对应的beanName已经注册且在配置中配置了bean不允许被覆盖,则抛出异常
         throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (logger.isInfoEnabled()) {
            logger.info("Overriding user-defined bean definition for bean '" + beanName +
                  "' with a framework-generated bean definition: replacing [" +
                  existingDefinition + "] with [" + beanDefinition + "]");
         }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
         if (logger.isDebugEnabled()) {
            logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      // 注册beanDefinition
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            removeManualSingletonName(beanName);
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (existingDefinition != null || containsSingleton(beanName)) {
      // 重置所有beanName对应的缓存
      resetBeanDefinition(beanName);
   }
   else if (isConfigurationFrozen()) {
      clearByTypeCache();
   }
}

一共分为4个步骤。

  1. 针对AbstractBeanDefinition的methodOverride属性进行校验,这里的methodOverride存放的实际上就是<look-up><replaced-method>两个子标签所解析的结果。
  2. bean已经注册过的情况处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖。
  3. 加入beanDefinitionMap中缓存,使用ConcurrentHashMap进行并发访问。
  4. 清除解析之前留下的对应的bean的缓存,例如解决循环依赖时使用的缓存singletonObjectsearlySingletonObjects等。

1.4.2 通过别名注册BeanDefinition

通过别名注册BeanDefinitionregisterAlias方法是在SimpleAliasRegistry类中定义的。

public void registerAlias(String name, String alias) {
   Assert.hasText(name, "'name' must not be empty");
   Assert.hasText(alias, "'alias' must not be empty");
   synchronized (this.aliasMap) {
      if (alias.equals(name)) {
         // alias与beanName相同,从aliasMap中移除该alias
         this.aliasMap.remove(alias);
         if (logger.isDebugEnabled()) {
            logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
         }
      }
      else {
         String registeredName = this.aliasMap.get(alias);
         if (registeredName != null) {
            if (registeredName.equals(name)) {
               // 该alias被使用并且指向的是当前beanName
               return;
            }
            // 该alias被使用但是指向的是另外的bean
            if (!allowAliasOverriding()) {
               // 若用户不允许alias覆盖则抛出异常
               throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                     name + "': It is already registered for name '" + registeredName + "'.");
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                     registeredName + "' with new target name '" + name + "'");
            }
         }
         // 当A->B存在时,若再次出现A->C->B时会出现异常
         checkForAliasCircle(name, alias);
         this.aliasMap.put(alias, name);
         if (logger.isTraceEnabled()) {
            logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
         }
      }
   }
}

由以上代码可知,注册alias的步骤如下:

  1. aliasbeanName相同时,不需要处理并移除原有的alias
  2. alias已经使用并指向了另外的beanName,则根据用户是否允许alias覆盖进行处理。
  3. alias循环检查。
  4. 注册alias

2 alias标签的解析

在上一节中已经讲过了对于beanname元素的解析,那么现在再来看一下alias标签的解析过程。

protected void processAliasRegistration(Element ele) {
   String name = ele.getAttribute(NAME_ATTRIBUTE);
   String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
   boolean valid = true;
   if (!StringUtils.hasText(name)) {
      getReaderContext().error("Name must not be empty", ele);
      valid = false;
   }
   if (!StringUtils.hasText(alias)) {
      getReaderContext().error("Alias must not be empty", ele);
      valid = false;
   }
   if (valid) {
      try {
         getReaderContext().getRegistry().registerAlias(name, alias);
      }
      catch (Exception ex) {
         getReaderContext().error("Failed to register alias '" + alias +
               "' for bean with name '" + name + "'", ele, ex);
      }
      getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
   }
}

可以发现,跟之前讲过的bean中的alias解析大同小异,都是将别名与beanName组成键值对注册至registry中。

原文地址:https://www.cnblogs.com/muuu520/p/14448393.html