关于spring:Spring源码之默认标签解析及BeanDefinition注册

69次阅读

共计 30578 个字符,预计需要花费 77 分钟才能阅读完成。

开篇

上一篇解说了 Spring 中的标签蕴含自定义标签和默认标签,这两种形式存在较大不同,所以本文次要解说默认标签的解析过程。

默认标签的解析是在 parseDefaultElement 办法中。

该办法别离对不同标签做不同解决。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   // 对 import 标签解决
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);
   }
   // 对 alias 标签解决
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);
   }
   // 对 bean 标签解决
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);
   }
   // 对 beans 标签解决
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {doRegisterBeanDefinitions(ele);
   }
}

Bean 标签的解析及注册

这四种中,咱们次要关注 对 bean 标签的解析。bean 标签的解析是最简单且重要的。咱们进入 processBeanDefinition 办法。

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

该段代码咱们还是先看时序图。

该办法 processBeanDefinition 大抵逻辑如下:

  1. 首先调用了 delegate.parseBeanDefinitionElement(ele) 办法进行元素解析。并返回 BeanDefinitionHolder 类型的 bdHolder,通过这个办法后,bdHolder 实例中曾经蕴含了配置文件中的各种属性,比方 class,name,id,alias 等
  2. 当返回的 bdHolder 不为空的状况下,若存在默认标签的子节点下还有自定义属性,还要对自定义标签进行解析。
  3. 解析实现后,须要对解析后的 bdHolder 进行注册,注册操作委托给了BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 办法
  4. 最初收回响应事件,告诉相干监听器,该 bean 曾经加载实现

解析 BeanDefinition

接下来咱们一点点剖析,首先咱们剖析该办法delegate.parseBeanDefinitionElement(ele)

该办法在 BeanDefinitionParserDelegate 类中。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   // 解析 id 属性
   String id = ele.getAttribute(ID_ATTRIBUTE);
   // 解析 name 属性
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
   // 宰割 name 属性
   List<String> aliases = new ArrayList<>();
   if (StringUtils.hasLength(nameAttr)) {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);
   }
   // 代码(1)AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {if (!StringUtils.hasText(beanName)) {
         try {
            // 如果不存在 beanName 那么依据 Spring 中提供的命名规定为以后 bean 生成对应的 beanName
            if (containingBean != null) {
               beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {beanName = this.readerContext.generateBeanName(beanDefinition);
               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);
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}

该办法就是对默认标签解析的全过程,咱们当初能够能够看到对属性 id、name 的解析。

在以后办法次要实现的内容如下:

  1. 提取元素 id、name 属性
  2. 解析其余属性并封装到 GenericBeanDefinition 类型实例中
  3. 如果检测到 bean 没有指定 beanName,则应用默认规定生成一个 beanName
  4. 将获取到的信息封装到 BeanDefinitionHolder 实例中

咱们看一下代码中标注的代码(1)调用的 parseBeanDefinitionElement 办法是如何对其余标签进行解析的。

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));
   String className = null;
   // 解析 class 属性
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim();}
   String parent = null;
   // 解析 parent 属性
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }

   try {
      // 代码(1)创立用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 代码(2)解析默认 bean 的各种属性
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      // 提取 description
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
      // 代码(3)解析元数据
      parseMetaElements(ele, bd);
      // 解析 lookup-medthod 属性(用的很少,这里就不深刻介绍)parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      // 解析 replace-medthod 属性(用的很少,这里就不深刻介绍)parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
      // 代码(4)解析结构函数参数
      parseConstructorArgElements(ele, bd);
      // 代码(5)解析 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;
}

创立用于属性承载的 BeanDefinition

咱们先看一下代码(1)调用的办法之前,咱们先再理解一下 BeanDefinition。

BeanDefinition 是一个接口,在 Spring 中存在三种实现:RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition。它们均继承自 AbstractBeanDefinition,其中 BeanDefinition 是配置文件<bean> 元素在容器外部的表现形式。该标签领有 class、scope、lazy-init 等配置属性,BeanDefinition 也提供了对应的属性:beanClass、scope、lazyInit。

其中 RootBeanDefinition 是最罕用的实现类,个别对应 <bean> 元素标签,而 GenericBeanDefinition 是 2.5 版本后退出的 bean 文件配置属性定义类,提供一站式服务类。

在配置文件中咱们能够父 <bean> 和子 <bean>,父就用 RootBeanDefinition 示意,而子就应用 ChildBeanDefinition 示意。一般的<bean> 就应用 RootBeanDefinition 来示意,AbstractBeanDefinition 则对两者独特类的信息进行形象。

Spring 通过 BeanDefinition 将配置文件的 <bean> 转换为容器外部示意,并且将这些 BeanDefinition 注册到 BeanDefinitionRegistry 中。

Spring 容器的 BeanDefinitionRegistry 次要以 map 模式存储,后续操作能够间接从该类中获取配置信息。

但首先,咱们解析属性之前就须要创立用于承载属性的实例,也就是创立了咱们之前说的 GenericBeanDefinition 类型的实例。也就是代码(1)调用的 createBeanDefinition(className, parent) 办法。

protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
      throws ClassNotFoundException {

   return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
}
public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {GenericBeanDefinition bd = new GenericBeanDefinition();
   // 如果没有父类,parentName 则为空
   bd.setParentName(parentName);
   if (className != null) {
      // 如果 classLoader 不为空则应用传入的 classLoader 进行加载类对象,否则只是记录 className
      if (classLoader != null) {bd.setBeanClass(ClassUtils.forName(className, classLoader));
      }else {bd.setBeanClassName(className);
      }
   }
   return bd;
}

至此,咱们就创立好了 GenericBeanDefinition 实例。

解析各种属性

当创立完用来承载 Bean 信息的 GenericBeanDefinition 实例后,就能够对 bean 信息的各种属性进行解析了。

首先咱们进入代码(2)parseBeanDefinitionAttributes办法,该办法对 element 所有元素属性进行解析。

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

    // 解析 singleton 属性
   if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
      // singleton 属性曾经不被反对,应用 scope 代替
      error("Old 1.x'singleton'attribute in use - upgrade to'scope'declaration", ele);
   }
   // 解析 scope 属性
   else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
   }
   else if (containingBean != null) {
      // 在嵌入 BeanDefinition 状况下,并且没有独自指定 scope 属性,则应用父类默认的属性
      bd.setScope(containingBean.getScope());
   }
   // 解析 abstract 属性
   if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
   }
   // 解析 lazy-init 属性
   String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
   if (isDefaultValue(lazyInit)) {lazyInit = this.defaults.getLazyInit();
   }
   bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
   // 解析 autowire 属性
   String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
   bd.setAutowireMode(getAutowireMode(autowire));
    // 解析 depends-on 属性
   if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
      bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
   }
    // 解析 autowire-candidate 属性
   String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
   if (isDefaultValue(autowireCandidate)) {String candidatePattern = this.defaults.getAutowireCandidates();
      if (candidatePattern != null) {String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
         bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
      }
   }
   else {bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
   }

    // 解析 primary 属性
   if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
   }

   // 解析 init-method 属性
   if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
      bd.setInitMethodName(initMethodName);
   }
   else if (this.defaults.getInitMethod() != null) {bd.setInitMethodName(this.defaults.getInitMethod());
      bd.setEnforceInitMethod(false);
   }
   // 解析 destroy-method 属性
   if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
      bd.setDestroyMethodName(destroyMethodName);
   }
   else if (this.defaults.getDestroyMethod() != null) {bd.setDestroyMethodName(this.defaults.getDestroyMethod());
      bd.setEnforceDestroyMethod(false);
   }
   // 解析 factory-method 属性
   if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
   }
   // 解析 factory-bean 属性
   if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
   }

   return bd;
}

该办法次要做的就是拿到各种属性对应的属性值放入 AbstractBeanDefinition 对应属性中。

解析子元素 meta

首先咱们回顾一下如何应用 meta 属性。

<bean id="myTestBean" class="cn.jack.MyTestBean">
        <meta key="jack" value="HelloWorld"/>
</bean>
public class MyTestBean {

    private String testStr = "testStr";

    public String getTestStr() {return testStr;}

    public void setTestStr(String testStr) {this.testStr = testStr;}
}

这段代码并没有体现在 MyTestBean 中,只是一个申明,在应用的时候能够 应用 BeanDefinition 类的 getAttribute(key)办法获取。

接下来咱们看一下是如何解析的,进入代码(3)。

public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
   // 获取以后节点所有元素
   NodeList nl = ele.getChildNodes();
   for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
      // 判断节点是否为 meta
      if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {Element metaElement = (Element) node;
         String key = metaElement.getAttribute(KEY_ATTRIBUTE);
         String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
         // 结构 BeanMetadataAttribute 实例
         BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
         attribute.setSource(extractSource(metaElement));
         // 记录信息
         attributeAccessor.addMetadataAttribute(attribute);
      }
   }
}

解析子元素 constructor-arg

对构造函数的解析还是十分常见的,同时也是很简单,举个例子:

<bean id="myTestBean" class="cn.jack.MyTestBean">
        <constructor-arg index="0">
            <value>Jack</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>hello</value>
        </constructor-arg>
</bean>

该代码就是 Spring 中最根底的配置,主动寻找对应的结构器并在初始化的时候将设置的参数传入进去,接下来看一下如何解析。

public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
   // 拿到 bean 所有子节点
   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)) {
         // 解析 constructor-arg
         parseConstructorArgElement((Element) node, bd);
      }
   }
}

进入 parseConstructorArgElement 办法。

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));
                        // 代码(1)解析 ele 对应的属性元素
                        Object value = parsePropertyValue(ele, bd, null);
                        // 应用 ConstructorArgumentValues.ValueHolder 类型封装解析进去的元素
                        ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                        // 将 name 属性和 type 都封装到 valueHolder 中
                        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 {
                            // 增加到 BeanDefinition 的 ConstructorArgumentValues 中, 存入构造为 Map
                            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());
                // 解析 ele 节点对应的属性值
                Object value = parsePropertyValue(ele, bd, null);
                // 应用 ConstructorArgumentValues.ValueHolder 类型封装解析进去的元素
                ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                // 将 name 属性和 type 都封装到 valueHolder 中
                if (StringUtils.hasLength(typeAttr)) {valueHolder.setType(typeAttr);
                }
                if (StringUtils.hasLength(nameAttr)) {valueHolder.setName(nameAttr);
                }
                valueHolder.setSource(extractSource(ele));
                // 增加到 BeanDefinition 的 ConstructorArgumentValues 中, 因为没有 index 则存入构造为 List
                bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
            }
            finally {this.parseState.pop();
            }
        }
}

该办法并不是特地简单,首先提取 constructor-arg 上必要的属性(index、type、name)。

配置中指定了 index 的话操作步骤如下:

  1. 解析 constructor-arg 的子元素
  2. 应用 ConstructorArgumentValues.ValueHolder 类型封装解析后的元素
  3. 最初将 index、name、type 封装到 ValueHolder 类型中,并增加到 BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中。

配置中没有指定 index 的话操作步骤如下:

  1. 解析 constructor-arg 的子元素
  2. 应用 ConstructorArgumentValues.ValueHolder 类型封装解析后的元素
  3. 最初将 index、name、type 封装到 ValueHolder 类型中,并增加到 BeanDefinition 的 constructorArgumentValues 的 genericArgumentValues 属性中。

理解完流程之后,咱们看一下具体是如何进行解析的,进入代码(1)parsePropertyValue的办法中。

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

   // 获取 ele 节点的子节点, 一个属性只能对应一种类型:ref/value/list 等
   NodeList nl = ele.getChildNodes();
   Element subElement = null;
   for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
      // 跳过 meta 节点或 description 节点
      if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
            !nodeNameEquals(node, META_ELEMENT)) {
         // 只能有一个子节点, 否则异样
         if (subElement != null) {error(elementName + "must not contain more than one sub-element", ele);
         }
         else {
            // 把子节点赋值给 subElement
            subElement = (Element) node;
         }
      }
   }
       // 解析 constructor-arg 的 ref 属性
   boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
   // 解析 constructor-arg 的 value 属性
   boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
   // 在 constructor-arg 中不存在: 1. 既有 ref 又有 value 属性 2. 存在 ref 或者 value 属性并且有子元素
   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) {
      // 解析子元素
      return parsePropertySubElement(subElement, bd);
   }
   else {
      // 如果没有 ref 和 value, 也没有子元素则抛出异样
      // Neither child element nor "ref" or "value" attribute found.
      error(elementName + "must specify a ref or value", ele);
      return null;
   }
}

该办法对构造函数中属性的元素解析,通过以下过程:

  1. 跳过 description 或者 meta
  2. 提取 constructor-arg 上的 ref 和 value 属性,随后进行校验
  3. ref 属性解决,应用 RuntimeBeanReference 封装对应的 ref 名称,比方:

    <constructor-arg ref="a"></constructor-arg>
  4. value 属性的解决,应用 TypedStringValue 封装,比方:

    <constructor-arg value="a"></constructor-arg>
  5. 子元素解决,比方:

    <bean id="myTestBean" class="cn.jack.MyTestBean">
            <constructor-arg>
                <map>
                    <entry key="jack" value="nihao"></entry>
                </map>
            </constructor-arg>
    </bean>

对于子元素的解决,比方这里提到的退出了 map 元素,是如何解决的?具体在 parsePropertySubElement 中实现了各种子元素的解决。

public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {return parsePropertySubElement(ele, bd, null);
}
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
        // 判断是否为默认命名空间, 如果不是就进行解析自定义节点
        if (!isDefaultNamespace(ele)) {return parseNestedCustomElement(ele, bd);
        }
        // 解析是否为 bean 节点
        else if (nodeNameEquals(ele, BEAN_ELEMENT)) {BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
            if (nestedBd != null) {nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
            }
            return nestedBd;
        }
        // 解析 ref 标签
        else if (nodeNameEquals(ele, REF_ELEMENT)) {
            // A generic reference to any name of any bean.
            String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
            boolean toParent = false;
            if (!StringUtils.hasLength(refName)) {
                // A reference to the id of another bean in a parent context.
                // 解析 parent
                refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
                toParent = true;
                if (!StringUtils.hasLength(refName)) {error("'bean' or 'parent' is required for <ref> element", ele);
                    return null;
                }
            }
            if (!StringUtils.hasText(refName)) {error("<ref> element contains empty target attribute", ele);
                return null;
            }
            RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
            ref.setSource(extractSource(ele));
            return ref;
        }
        // 解析 idref 元素
        else if (nodeNameEquals(ele, IDREF_ELEMENT)) {return parseIdRefElement(ele);
        }
        // 解析 value 元素
        else if (nodeNameEquals(ele, VALUE_ELEMENT)) {return parseValueElement(ele, defaultValueType);
        }
        // 解析 null 元素
        else if (nodeNameEquals(ele, NULL_ELEMENT)) {
            // It's a distinguished null value. Let's wrap it in a TypedStringValue
            // object in order to preserve the source location.
            TypedStringValue nullHolder = new TypedStringValue(null);
            nullHolder.setSource(extractSource(ele));
            return nullHolder;
        }
        // 解析 array 元素
        else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {return parseArrayElement(ele, bd);
        }
        // 解析 list 元素
        else if (nodeNameEquals(ele, LIST_ELEMENT)) {return parseListElement(ele, bd);
        }
        // 解析 set 元素
        else if (nodeNameEquals(ele, SET_ELEMENT)) {return parseSetElement(ele, bd);
        }
        // 解析 map 元素
        else if (nodeNameEquals(ele, MAP_ELEMENT)) {return parseMapElement(ele, bd);
        }
        // 解析 props 元素
        else if (nodeNameEquals(ele, PROPS_ELEMENT)) {return parsePropsElement(ele);
        }
        else {error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
            return null;
        }
}

在该办法中实现了所有反对的类型的分类解决,到此就曾经理分明构造函数是如何解析了,这里就不深入研究如何解析 list、map 等元素了。

解析子元素 property

在剖析完构造函数后,咱们能够接着往下看,这里防止遗记咱们再看一下目前到哪里了。

到这里咱们先回顾一下如何应用 property 属性。当然,property 属性里也能够应用 list 等类型的元素。

<bean id="myTestBean" class="cn.jack.MyTestBean">
   <property name="testStr" value="jack"/>
</bean>
public class MyTestBean {

   private String testStr = "testStr";

   public String getTestStr() {return testStr;}

   public void setTestStr(String testStr) {this.testStr = testStr;}
}

接下来咱们看一下是如何解析的。

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
   // 获取到 beanElement 的所有子节点
   NodeList nl = beanEle.getChildNodes();
   for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);
      if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
         // 解析 property 节点
         parsePropertyElement((Element) node, bd);
      }
   }
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
   // 获取配置元素的 name 值
   String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
   if (!StringUtils.hasLength(propertyName)) {
      //name 为空则抛出异样
      error("Tag'property'must have a'name'attribute", ele);
      return;
   }
   this.parseState.push(new PropertyEntry(propertyName));
   try {
      // 校验在雷同 bean 节点下, 是否存在同样的 name 属性, 如果存在则抛出异样
      if (bd.getPropertyValues().contains(propertyName)) {error("Multiple'property'definitions for property'" + propertyName + "'", ele);
         return;
      }
      // 解析属性值
      Object val = parsePropertyValue(ele, bd, propertyName);
      // 解析后的值和 name 属性封装为 PropertyValue
      PropertyValue pv = new PropertyValue(propertyName, val);
      // 解析 meta 节点
      parseMetaElements(ele, pv);
      pv.setSource(extractSource(ele));
      // 解析实现后增加到 BeanDefinition 的 propertyValues 属性中
      bd.getPropertyValues().addPropertyValue(pv);
   }
   finally {this.parseState.pop();
   }
}

和之前解说的过程都差不多,都是先获取所有子标签而后进行遍历进行解析,获取对应的 name、value 值进行封装。

解析子元素 qualifier

该元素咱们个别应用注解偏多,次要就是当接口存在多个实现类时候,在咱们注入时指定某一个实现类,这样 Spring 容器就能够找到对应的 bean。因为在 Spring 中候选的 Bean 数目必须有且仅有一个。解析过程和之前都差不多,这里就不再赘述。

<bean id="myTestBean" class="cn.jack.MyTestBean">
   <qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="Bean 的名称"/>
</bean>

AbstractBeanDefinition 属性

AbstractBeanDefinition bd = createBeanDefinition(className, parent);

至此,咱们就实现了对 XML 文档到 GenericBeanDefinition 的转换,XML 中的配置都能够在 GenericBeanDefinition 中看到,但 GenericBeanDefinition 只是子类,大部分属性都在 AbstractBeanDefinition 中。咱们回顾一下都有哪些配置。

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
        implements BeanDefinition, Cloneable {

    // 此处省略动态变量以及 final 变量

    @Nullable
    private volatile Object beanClass;
    /**
     * bean 的作用范畴,对应 bean 属性 scope
     */
    @Nullable
    private String scope = SCOPE_DEFAULT;
    /**
     * 是否是形象,对应 bean 属性 abstract
     */
    private boolean abstractFlag = false;
    /**
     * 是否提早加载,对应 bean 属性 lazy-init
     */
    private boolean lazyInit = false;
    /**
     * 主动注入模式,对应 bean 属性 autowire
     */
    private int autowireMode = AUTOWIRE_NO;
    /**
     * 依赖查看,Spring 3.0 后弃用这个属性
     */
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;
    /**
     * 用来示意一个 bean 的实例化依附另一个 bean 先实例化,对应 bean 属性 depend-on
     */
    @Nullable
    private String[] dependsOn;
    /**
     * autowire-candidate 属性设置为 false,这样容器在查找主动拆卸对象时,* 将不思考该 bean,即它不会被思考作为其余 bean 主动拆卸的候选者,* 然而该 bean 自身还是能够应用主动拆卸来注入其余 bean 的
     */
    private boolean autowireCandidate = true;
    /**
     * 主动拆卸时呈现多个 bean 候选者时,将作为首选者,对应 bean 属性 primary
     */
    private boolean primary = false;
    /**
     * 用于记录 Qualifier,对应子元素 qualifier
     */
    private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);

    @Nullable
    private Supplier<?> instanceSupplier;
    /**
     * 容许拜访非公开的结构器和办法,程序设置
     */
    private boolean nonPublicAccessAllowed = true;
    /**
     * 是否以一种宽松的模式解析构造函数,默认为 true,* 如果为 false,则在以下状况
     * interface ITest{}
     * class ITestImpl implements ITest{};
     * class Main {*     Main(ITest i) {}
     *     Main(ITestImpl i) {}
     * }
     * 抛出异样,因为 Spring 无奈精确定位哪个构造函数程序设置
     */
    private boolean lenientConstructorResolution = true;
    /**
     * 对应 bean 属性 factory-bean,用法:* <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
     * <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
     */
    @Nullable
    private String factoryBeanName;
    /**
     * 对应 bean 属性 factory-method
     */
    @Nullable
    private String factoryMethodName;
    /**
     * 记录构造函数注入属性,对应 bean 属性 constructor-arg
     */
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;
    /**
     * 一般属性汇合
     */
    @Nullable
    private MutablePropertyValues propertyValues;
    /**
     * 办法重写的持有者,记录 lookup-method、replaced-method 元素
     */
    @Nullable
    private MethodOverrides methodOverrides;
    /**
     * 初始化办法,对应 bean 属性 init-method
     */
    @Nullable
    private String initMethodName;
    /**
     * 销毁办法,对应 bean 属性 destroy-method
     */
    @Nullable
    private String destroyMethodName;
    /**
     * 是否执行 init-method,程序设置
     */
    private boolean enforceInitMethod = true;
    /**
     * 是否执行 destroy-method,程序设置
     */
    private boolean enforceDestroyMethod = true;
    /**
     * 是否是用户定义的而不是应用程序自身定义的,创立 AOP 时候为 true,程序设置
     */
    private boolean synthetic = false;
    /**
     * 定义这个 bean 的利用,APPLICATION:用户,INFRASTRUCTURE:齐全外部应用,与用户无关,* SUPPORT:某些简单配置的一部分
     * 程序设置
     */
    private int role = BeanDefinition.ROLE_APPLICATION;
    /**
     * bean 的形容信息
     */
    @Nullable
    private String description;
    /**
     * 这个 bean 定义的资源
     */
    @Nullable
    private Resource resource;
}

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

到目前为止,咱们曾经剖析了 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 这行代码,接下来咱们持续剖析 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 这行代码。

咱们先理解一下这行代码的大略作用,从语义上来剖析:如果需要的话就对 BeanDefinition 进行装璜,相似于如下场景:

<bean id="myTestBean" class="cn.jack.MyTestBean">
        <mybean:user username="jack"/>
</bean>

当 Spring 中的 bean 应用的是默认标签配置,然而子元素却应用自定义配置的时候,这行代码就会执行。

然而为什么会在默认类型解析中独自增加一个自定义类型呢?首先这个自定义类型并不是以 bean 的模式呈现的,在这里的自定义类型其实相当于是属性。

咱们持续剖析该办法代码。

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

在调用 decorateBeanDefinitionIfRequired 办法时,第三个参数传入为 null,该参数是父类 bean,当对某个嵌套配置剖析时须要传递父类的 BeanDefinition,其实就是为了应用父类的 scope 属性,如果子类没有设置 scope 属性则应用父类的 scope 属性。这里是顶层配置,所以传递为 null。

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

        BeanDefinitionHolder finalDefinition = originalDef;

        // 遍历节点, 查看是否存在实用于装璜的属性
        // Decorate based on custom attributes first.
        NamedNodeMap attributes = ele.getAttributes();
        for (int i = 0; i < attributes.getLength(); i++) {Node node = attributes.item(i);
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }
        // 遍历子节点, 查看是否存在实用于装璜的属性
        // Decorate based on custom nested elements.
        NodeList children = ele.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {Node node = children.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
            }
        }
        return finalDefinition;
}

最终都调用到了 decorateIfRequired 办法,咱们进入此办法查看。

public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
       // 获取自定义命名空间
   String namespaceUri = getNamespaceURI(node);
   // 过滤默认命名空间
   if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
      // 依据命名空间找到相应的处理器
      NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
      if (handler != null) {
         // 进行装璜解决
         BeanDefinitionHolder decorated =
               handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
         if (decorated != null) {return decorated;}
      }
      else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
      }
      else {
         // A custom namespace, not to be handled by Spring - maybe "xml:...".
         if (logger.isDebugEnabled()) {logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
         }
      }
   }
   return originalDef;
}

到这里曾经很明确了,首先获取元素或者属性的命名空间,而后判断是否实用于自定义标签的解析条件,随后找到对应的 NamespaceHandler 进行下一步解析,该局部会在自定义标签解析中解说。

总结:该办法的作用就是对自定义标签或者自定义属性进行解决,而后找到对应的命名空间处理器进行进一步的解析。

注册解析的 BeanDefinition

到这里,咱们对配置文件的解析、装璜都曾经实现,当初的 BeanDefinition 曾经满足应用要求了,后续就剩下了注册工作。

也就是 processBeanDefinition 办法中的 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);
      }
   }
}

该办法获取到 beanName 后,最终 BeanDefinition 都会注册到 BeanDefinitionRegistry 中,该办法分为两局部,一种为 beanName 注册形式和别名注册形式。

对于 BeanDefinition 的注册,不仅仅是将 BeanDefinition 放入 map 中,而后 beanName 作为 key。除此之外还做了别的事件。

进入 DefaultListableBeanFactory 类实现中。

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 {
                // 注册前最初一次校验, 针对 AbstractBeanDefinition 中的 methodOverrides 校验
                // 校验 methodOverrides 是否与工厂办法并存, 或者 methodOverrides 对应的办法压根不存在
                ((AbstractBeanDefinition) beanDefinition).validate();}
            catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
        // 判断是否曾经存在 bean
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            // 如果对应的 beanName 曾经注册过并且不容许笼罩, 则抛出异样
            if (!isAllowBeanDefinitionOverriding()) {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 {
            // 是否曾经开始创立 bean
            if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)
                // 因为 beanDefinitionMap 是全局变量,这里会存在并发拜访的状况
                synchronized (this.beanDefinitionMap) {
                    // 存入 BeanDefinition
                    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
                // 存入 BeanDefinition
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 记录 beanName
                this.beanDefinitionNames.add(beanName);
                // 从 factoryBeanCreatedCache 中移除掉这个 beanName
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

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

注册 bean 分为以下四步:

  1. 对 AbstractBeanDefinition 的 methodOverrides 属性校验
  2. 如果曾经注册过并且不容许笼罩则抛出异样,否则间接笼罩
  3. 退出 map 缓存
  4. 革除解析前的 beanName 缓存

之后咱们再看通过别名注册就简略多了。

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) {
      // 如果 beanName 与 alias 雷同则不记录 alias, 并删除对应的 alias
      if (alias.equals(name)) {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)) {
               // An existing alias - no need to re-register
               return;
            }
            // 不容许笼罩则抛出异样
            if (!allowAliasOverriding()) {
               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 + "'");
            }
         }
         // 确保增加的没有 name 和 alias 值相同的数据且 alias 和 name 不相等
         checkForAliasCircle(name, alias);
         // 存入 map 中
         this.aliasMap.put(alias, name);
         if (logger.isTraceEnabled()) {logger.trace("Alias definition'" + alias + "'registered for name'" + name + "'");
         }
      }
   }
}

从该办法可知,注册 alias 步骤如下:

  1. alias 和 beanName 雷同状况解决,如果雷同则不须要解决并删除原有 alias
  2. 笼罩校验解决
  3. alias 循环查看
  4. 注册 alias

告诉监听器解析及注册实现

在注册实现后,当开发人员须要对注册 BeanDefinition 事件进行监听时能够通过注册监听器形式将解决逻辑写入监听器中,在 Spring 中并没有对此事件做任何逻辑解决。

总结

到这里,Bean 的解析和注册过程曾经全副 OK 了。

回顾一下,解析 BeanDefinition 的入口在 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()。该办法会依据命令空间来判断标签是默认标签还是自定义标签,其中默认标签由 parseDefaultElement() 实现,自定义标签由 parseCustomElement() 实现。在默认标签解析中,会依据标签名称的不同进行 import、alias、bean、beans 四大标签进行解决,其中 bean 标签的解析为外围,它由 processBeanDefinition() 办法实现。processBeanDefinition() 开始进入解析外围工作,分为三步:

  1. 解析默认标签:BeanDefinitionParserDelegate.parseBeanDefinitionElement()
  2. 解析默认标签下的自定义标签:BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()
  3. 注册解析的 BeanDefinition:BeanDefinitionReaderUtils.registerBeanDefinition()

在默认标签解析过程中,外围工作由 parseBeanDefinitionElement() 办法实现,该办法会顺次解析 Bean 标签的属性、各个子元素,解析实现后返回一个 GenericBeanDefinition 实例对象。

最初通过 registerBeanDefinition 办法进行对 BeanDefinition 进行注册后就功败垂成了。

正文完
 0