zoukankan      html  css  js  c++  java
  • Spring IoC 默认标签解析

    前言

    本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。

    本篇文章主要介绍 Spring IoC 容器怎么解析默认标签的。

    正文

    所谓的默认标签就是 importaliasbeanbeans 这四个标签。

    DefaultBeanDefinitionDocumentReader#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);
        }
    }
    

    上面 parseDefaultElement 方法中对 bean 标签的处理方法 processBeanDefinition 最为重要,下面来着重分析一下。

    DefaultBeanDefinitionDocumentReader#processBeanDefinition

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 将ele解析成BeanDefinitionHolder,见下文详解
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            // 若存在默认标签下的子节点下不再有自定义属性,需要再次对自定义标签再进行解析(基本不用,不做深入分析)
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // 注册最终的BeanDefinition,见下文详解
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                                         bdHolder.getBeanName() + "'", ele, ex);
            }
            // 发出响应事件,通知相关监听器,这个bean已经注册完
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    

    BeanDefinitionParseDelegate#parseBeanDefinitionElement

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
        // 解析元素,封装成BeanDefinitionHolder
        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);
        List<String> aliases = new ArrayList<>();
        // 将name属性所有的名称按照逗号或者分号(,;),分割成数组放入别名集合aliases
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
        // beanName默认使用id
        String beanName = id;
        // 没有指定id属性 && 指定了name属性
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            // 如果没有指定id,beanName等于第一个别名,剩下的依然作为别名使用
            beanName = aliases.remove(0);
        }
    
        if (containingBean == null) {
            // 验证beanName和aliases是否在同一个<beans>下已经存在
            checkNameUniqueness(beanName, aliases, ele);
        }
        // 将元素解析成GenericBeanDefinition
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            // 如果不存在beanName会根据Spring的命名规则生成一个
            if (!StringUtils.hasText(beanName)) {
                try {
                    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);
                        }
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            // 用beanDefinition和beanName以及aliasesArray构建BeanDefinitionHolder
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }
        return null;
    }
    
    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 {
            // 创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 解析默认bean的各种属性,见下文详解
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            // 提取description
    		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            // 解析元数据,见下文详解
            parseMetaElements(ele, bd);
            // 解析lookup-method属性,很少使用,不具体介绍
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            // 解析replaced-method属性,很少使用,不具体介绍
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            // 解析constructor-arg属性,见下文详解
            parseConstructorArgElements(ele, bd);
            // 解析property属性,见下文详解
            parsePropertyElements(ele, bd);
            // 解析qualifier属性,见下文详解
            parseQualifierElements(ele, bd);
           
            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));
            return bd;
        }
        // 省略异常处理...
        finally {
            this.parseState.pop();
        }
        return null;
    }
    

    上面方法中的 BeanDefinitionReaderUtils.generateBeanName() 方法会为 bean 生成一个默认的名称,主要规则如下:

    1. 获取 bean 的全类名,例如 com.leisurexi.ioc.domain.User;如果 beanparent 不为空那么 bean 的名称为 parentName 加上 $child,例如 userparent 是名称为 parentUserbean,那么当 user 未指定 beanName 时会其生成一个 parentUser$child 的名称;如果 beanparent 为空但 factory-bean 属性不为空,那就用该名称加上 $created 为其生成名称。
    2. 未指定 parentfactory-bean 属性,那么如果是内嵌 bean 则用全类名加上 # 和转换为十六进制字符串的 hashcode 拼成的字符串当做名称;不是内嵌 bean 就用全类名加上 # 和数字当做名称,如第一个 User 类型的自动生成的名称为 com.leisurexi.ioc.domain.User#0,第二个就是 com.leisurexi.ioc.domain.User#1

    我们这边可以简单看一下 BeanDefinitionHolder 的属性,如下:

    public class BeanDefinitionHolder implements BeanMetadataElement {
    	
        // bean 的定义元信息
        private final BeanDefinition beanDefinition;
        // bean 的名称
        private final String beanName;
        // bean 的别名数组
        @Nullable
        private final String[] aliases;
    
        // 省略其它代码...
    }
    

    BeanDefinitionParserDelegate#parseBeanDefinitionAttributes

    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));
        }
        // 如果是内嵌bean,则使用上级bean的scope值
        else if (containingBean != null) {
            bd.setScope(containingBean.getScope());
        }
        // 解析abstract属性
        if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
            bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
        }
        // 解析lazy属性
        String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
        // 若没有设置或者设置成其他字符都会被设置为默认值false
        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属性,该属性为false代表该bean不会被选为依赖注入的对象,默认为true
        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);
        }
        // 如果bean没有指定init-method属性,但beans标签指定了default-init-method属性,则会使用该属性
        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);
        }
        // 如果bean没有指定destroy-method属性,但beans标签指定了default-destroy-method属性,则会使用该属性
        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;
    }
    

    上面方法完成了对所有 bean 标签属性的解析。值得注意的地方是如果同时指定了 bean 标签的 init-methodbeans 标签的 default-init-method 属性,那么优先使用前者,destory-mehtod 标签也是一样。

    大家可以去看一下 AbstractBeanDefinition 中定义的属性就一目了然了,这里限于篇幅原因就不展示了。

    BeanDefinitionParserDelegate#parseConstructorArgElements

    public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
        // 获取所有子节点
        NodeList nl = beanEle.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            // 提取 constructor-arg
            if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
                // 解析 constructor-arg
                parseConstructorArgElement((Element) node, bd);
            }
        }
    }
    // <constructor-arg index="0" type="" value=""/>
    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);
        // index 不为空
        if (StringUtils.hasLength(indexAttr)) {
            try {
                // 转换为 int 类型
                int index = Integer.parseInt(indexAttr);
                if (index < 0) {
                    error("'index' cannot be lower than 0", ele);
                }
                else {
                    try {
                        this.parseState.push(new ConstructorArgumentEntry(index));
                        // 解析属性值,见下文详解
                        Object value = parsePropertyValue(ele, bd, null);
                        // 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素
                        ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                        // 如果 type 不为空,设置 ValueHolder 的 type
                        if (StringUtils.hasLength(typeAttr)) {
                            valueHolder.setType(typeAttr);
                        }
                        // 如果 name 不为空,设置 ValueHolder 的 name
                        if (StringUtils.hasLength(nameAttr)) {
                            valueHolder.setName(nameAttr);
                        }
                        valueHolder.setSource(extractSource(ele));
                        // 判断 index 是否重复,重复则抛出异常
                        if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {							
                            error("Ambiguous constructor-arg entries for index " + index, ele);
                        }
                        // 将 index 和 valueHolder 以 key-value的形式 添加到 BeanDefinition 的 ConstructorArgumentValues 当中
                        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 {
            try {
                // 这里就是 constructor-arg 标签中没有指定 index 属性
                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));
                // 将 valueHolder 添加 BeanDefinition 的 GenericArgumentValue 中
                // 这里和上面的 IndexedArgumentValue 类似,只不过上面是 Map,这里是 List
                bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
            }
            finally {
                this.parseState.pop();
            }
        }
    }
    

    上面代码首先提取 constructor-arg 标签中必要的属性 (indextypename)。

    • 如果指定了 index 属性:
      1. 解析 constructor-arg 的子元素。
      2. 使用 ConstructorArgumentsValues.ValueHolder 类型来封装解析出来的元素。
      3. typenameindex 属性一并封装在 ConstructorArgumentsValues.ValueHolder 类型中,并添加到当前 BeanDefinitionConstructorArgumentValues 中的 LinkedHashMap 类型的属性indexedArgumentValues 中。
    • 如果没有指定 index 属性:
      1. 解析 constructor-arg 的子元素。
      2. 使用 ConstructorArgumentsValues.ValueHolder 类型来封装解析出来的元素。
      3. typenameindex 属性一并封装在 ConstructorArgumentsValues.ValueHolder 类型中,并添加到当前 BeanDefinitionConstructorArgumentValues 中的 ArrayList 类型的属性genericArgumentValues 中。

    BeanDefinitionParserDelegate#parsePropertyValue

    public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
        String elementName = (propertyName != null ?
                              "<property> element for property '" + propertyName + "'" :
                              "<constructor-arg> element");
        // 获取所有子节点,例如list、map等
        NodeList nl = ele.getChildNodes();
        Element subElement = null;
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            // 跳过 description 或者 meta 不处理
            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;
                }
            }
        }
        // 提取 ref 属性
        boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
        // 提取 value 属性
        boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
        // 如果同时有 ref 和 value 属性 || 有 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);
        }
        // 只有 ref 属性,使用 RuntimeBeanReference 封装对应的 ref 名称 (该 ref 值指向另一个 bean 的 beanName)
        // RuntimeBeanReference 起到占位符的作用, ref 指向的 beanName 将在运行时被解析成真正的 bean 实例引用
        if (hasRefAttribute) {
            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;
        }
        // 只有 value 属性,使用 TypedStringValue 封装
        else if (hasValueAttribute) {
            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,直接抛出异常
            error(elementName + " must specify a ref or value", ele);
            return null;
        }
    }
    
    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)) {
            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.
                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)) {
            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;
        }
    }
    

    从上面的代码来看,对构造函数中属性元素的解析,步骤如下:

    1. 略过 description 或者 meta
    2. 提取 constructor-arg 上的 refvalue 属性,以便于根据规则验证正确性。其规则为在 constructor-arg 上不存在以下情况:
      • 同时存在 refvalue 属性。
      • 存在 ref 或者 value 属性,并且又有子元素。

    BeanDefinitionParserDelegate#parsePropertyElements

    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)) {
                // 解析 property 节点
                parsePropertyElement((Element) node, bd);
            }
        }
    }
    
    // 这里是解析 property 标签,<property name="..." value="..."/>
    public void parsePropertyElement(Element ele, BeanDefinition bd) {
        // 获取 name 属性
        String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
        // name 为空,抛出异常
        if (!StringUtils.hasLength(propertyName)) {
            error("Tag 'property' must have a 'name' attribute", ele);
            return;
        }
        this.parseState.push(new PropertyEntry(propertyName));
        try {
            // 出现两个 name 相同的抛出异常
            if (bd.getPropertyValues().contains(propertyName)) {
                error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
                return;
            }
            // 解析属性值,跟构造器解析一样
            Object val = parsePropertyValue(ele, bd, propertyName);
            // 用 name 和 val 封装成 PropertyValue
            PropertyValue pv = new PropertyValue(propertyName, val);
            // 解析元数据,跟 beans 标签内的 meta 一样
            parseMetaElements(ele, pv);
            pv.setSource(extractSource(ele));
            // 添加到 BeanDefinition 的 PropertyValues 属性中
            bd.getPropertyValues().addPropertyValue(pv);
        }
        finally {
            this.parseState.pop();
        }
    }
    

    上面方法主要是遍历 property 节点,然后解析属性值封装成 PropertyValue 添加到 BeanDefinitionPropertyValues 中。

    注意:property 标明的属性必需有 set 方法否则在赋值阶段会抛出异常。

    BeanDefinitionParserDelegate#parseQualifierElements

    public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
        // 获取子节点
        NodeList nl = beanEle.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
                // 解析 qualifier 节点
                parseQualifierElement((Element) node, bd);
            }
        }
    }
    
    public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
        // 提取 type
        String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
        // type 为空抛出异常
        if (!StringUtils.hasLength(typeName)) {
            error("Tag 'qualifier' must have a 'type' attribute", ele);
            return;
        }
        this.parseState.push(new QualifierEntry(typeName));
        try {
            AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
            qualifier.setSource(extractSource(ele));
            // 提取 value
            String value = ele.getAttribute(VALUE_ATTRIBUTE);
            // value 不为空,设置到 AutowireCandidateQualifier 的 attribute 中
            if (StringUtils.hasLength(value)) {
                qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
            }
            // 获取子节点
            NodeList nl = ele.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                // 如果是有 attribute 节点,进行解析,提取值放入到 AutowireCandidateQualifier 的MetadataAttribute 中
                if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
                    Element attributeEle = (Element) node;
                    String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
                    String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
                    if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
                        BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
                        attribute.setSource(extractSource(attributeEle));
                        qualifier.addMetadataAttribute(attribute);
                    }
                    else {
                        error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
                        return;
                    }
                }
            }
            // 设置 BeanDefinition 的 qualifier
            bd.addQualifier(qualifier);
        }
        finally {
            this.parseState.pop();
        }
    }
    

    对于 qualifier 元素的获取,我们大多数接触的更多是注解的形式,在使用 Spring 框架中进行自动注入时,Spring 容器中匹配的候选 Bean 必需有且只有一个。如果存在多个类型相同的 Bean,且按照类型注入时,Spring 允许通过 qualifier 指定注入 Bean 的名称,这样歧义就消除了。

    BeanDefinitionReaderUtils#registerBeanDefinition

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
    
        // Register bean definition under primary name.
        // 获取 beanName
        String beanName = definitionHolder.getBeanName();
        // 以 key-value 的形式注册,key 为 beanName,value 为 BeanDefinition。见下文详解
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
        // Register aliases for bean name, if any.
        // 注册 bean 的别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                // 以 key-value 的形式注册 bean 的别名,key 为别名,value 为 beanName。见下文详解
                registry.registerAlias(beanName, alias);
            }
        }
    }
    
    // DefaultListableBeanFactory.java
    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 {
                // 验证 Bean 的格式是否正确
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                       "Validation of bean definition failed", ex);
            }
        }
    
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        // 这里判断 BeanDefinition 是否存在
        if (existingDefinition != null) {
            // 这里就是如果 Bean 定义以及存在,判断是否可以覆盖,默认是可以的
            // Spring Boot 2.1开始这里会手动设置 allowBeanDefinitionOverriding 的值为 false
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            // 将 beanName 和 BeanDefinition 以 key-value 形式放入beanDefinitionMap 缓存中
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            // bean 是否已经开始创建
            if (hasBeanCreationStarted()) {
                synchronized (this.beanDefinitionMap) {
                    // 将 beanName 和 BeanDefinition 以 key-value 形式放入beanDefinitionMap 缓存中
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    // 这里将 beanDefinitionNames 写时复制一份,类似于 CopyOnWriteArrayList
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    // 从单例 Bean 注册名称列表中删除当前 beanName
                    removeManualSingletonName(beanName);
                }
            }
            // bean 不在创建状态中
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 因为 ConcurrentHashMap 是无序的,这里将 beanName 放入 ArrayList,记录注册顺序
                this.beanDefinitionNames.add(beanName);
                // 从单例 Bean 注册名称列表中删除当前 beanName
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }
        // 如果存在相同的 beanName 的 BeanDefinition,或者 beanName 已经存在单例对象,则将该 beanName 对应的缓存信息、单例对象清除,因为这些对象都是由老的 BeanDefinition 创建的,需要被覆盖掉。再用新的 BeanDefinition 来创建这些缓存和单例对象
        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }
    
    // SimpleAliasRegistry.java
    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 相同,从缓存中移除
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
            }
            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 + "'.");
                    }
                }
                // 检查 name 和 alias 是否存在循环引用。例如 A 的别名为 B,B的别名为A
                checkForAliasCircle(name, alias);
                // 将 alias 和 name 以 key-value 对放入到 aliasMap 中,进行缓存
                this.aliasMap.put(alias, name);
                }
            }
        }
    }
    

    上面代码有两个变量比较重要 beanDefinitionMapbeanDefinitionNames,下面代码是这两个属性在 DefaultListableBeanFactory 中的定义:

    public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
        
        // 缓存 BeanDefinition 的 Map,key 为 beanName,value 为 BeanDefinition
        private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
        // 保存 BeanDefinition 的注册顺序,保存的是 beanName
        private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
        
    }
    

    上面方法的主要流程如下:

    1. 如果 BeanDefinitionAbstractBeanDefinition 类型,验证 Bean 的格式是否正确。

      这次效验主要是对于 AbstractBeanDefinition 属性中的 methodOverrides 的校验,校验 methodOverrides 是否与 工厂方法 并存或者 methodOverrides 中的方法根本不存在。

    2. 判断该 beanNameBeanDefinition 是否已经注册过;如果存在判断是否允许覆盖,允许的话直接替换,不允许直接抛出异常。

      默认的情况下是允许的,但是在 Spring Boot 2.1 开始这里会手动的设置为不允许。

    3. beanName 对应的 BeanDefinition 以前没有注册过,判断 bean 是否已经开始创建;如果在创建中对 beanDefinitionMap 进行加锁 (这里虽然 beanDefinitionMap 是线程安全的 ConcurrentHashMap ,单个操作是线程安全的但多个操作不是,所以这里手动加锁),然后将 beanNameBeanDefinitionkey-value 形式放入 beanDefinitionMap 缓存中,然后写时复制一份 beanDefinitionNames ,将 beaName 缓存进去,记录 bean 的注册顺序;如果不在创建中直接将 BeanDefinitionbeanName 分别放入 beanDefinitionMapbeanDefinitionNames 中。

    4. 最后判断如果 BeanDefinition 已经注册过,或者 beanName 已经存在单例对象,则将该 beanName 对应的缓存信息、单例对象清除,因为这些对象都是由老的 BeanDefinition 创建的,需要被覆盖掉。再用新的 BeanDefinition 来创建这些缓存和单例对象。

    总结

    本文主要介绍了 Spring 对 XML 文件中 <bean> 标签的解析,我们可以重新梳理一下思路:

    1. 解析 <bean> 标签,构建成 AbstractBeanDefinition (GenericBeanDefinition) 对象来存放所有解析出来的属性。

    2. AbstractBeanDefinitionbeanNamealiasesArray 构建成 BeanDefinitionHolder 对象。

    3. 最后通过 BeanDefinitionHolderbeanNameBeanDefinition 注册到 DefaultListableBeanFactory 中,也就是保存起来。

      上文提到的两个比较重要的属性 beanDefinitionNamesbeanDefinitionMap ,在后面都会多次用到,可以重点关注一下。

    最后,我模仿 Spring 写了一个精简版,代码会持续更新。地址:https://github.com/leisurexi/tiny-spring

    参考

  • 相关阅读:
    springboot @value 注解的使用
    Django时间时区问题(received a naive datetime while time zone support is active
    乐观锁与悲观锁
    Django 从入门到放弃
    根据数据库表生成 model 类
    Django CSRF攻击
    Django的orm的 数据库查询语法大全
    js常用函数、书写可读性的js、js变量声明...
    Web Worker
    css编写规范
  • 原文地址:https://www.cnblogs.com/leisurexi/p/12748963.html
Copyright © 2011-2022 走看看