Spring IoC:parseDefaultElement详解(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/v123411739/article/details/86669952

前言

接着 Spring IoC:obtainFreshBeanFactory详解 上文继续往下解析,本文来到 parseDefaultElement 方法。该方法是解析默认命名空间节点的方法,是加载 Bean 定义模块的最核心方法。

 

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)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

可以看到默认命名空间的一级节点只有4种:import、alias、bean、beans。这4种节点中,最重要、最复杂的就是 <bean> 节点,本文只会介绍 <bean> 节点的处理,理解了 <bean> 节点后,其他的都不难理解。另外,<beans> 节点只是递归调用之前的 doRegisterBeanDefinitions 方法,因此无需再介绍。

接下来,让我们从 processBeanDefinition(ele, delegate) 方法正式开始。

 

processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 1.进行节点解析, 经过这个方法后,bdHolder已经包含我们配置文件中配置的各种属性了,例如name、class、id、alias之类的属性
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 2.若存在默认标签的子节点下再有自定义属性,需要再次对自定义标签再进行解析(基本不用,不做深入解析)
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            // 3.对解析后的bdHolder进行注册,注册操作委托给BeanDefinitionReaderUtils的registerBeanDefinition方法
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        } catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        // 4.最后发出响应事件,通知相关的监听器,这个bean已经加载完成了
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

1. 进行节点解析,见代码块1详解

2. 例如下图这种,基本不用,不做深入解析。

3. 对解析后的bdHolder进行注册,本文不介绍,parseDefaultElement详解(下)将进行详解

4. 发出响应事件,通知相关的监听器,不做深入解析。

由于篇幅关系,parseDefaultElement 方法的详解会分为上下两篇。上篇也就是本文,会对delegate.parseBeanDefinitionElement(ele) 方法进行详解;而下篇,会对 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()) 方法进行详解。

现在,让我们从 delegate.parseBeanDefinitionElement(ele) 方法开始吧。

 

代码块1:parseBeanDefinitionElement(ele)

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

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    // 1.解析name和id属性
    // 解析id属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    // 解析name属性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    // 分割name属性(通过逗号或分号)
    // 例如:<bean name="demoService,demoServiceAlias" class=""/>,分割后aliases为[demoService, demoServiceAlias]
    List<String> aliases = new ArrayList<String>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }

    // beanName默认使用id
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        // 如果id为空,并且aliases不为空,则取aliases的第一个元素作为beanName,其他的仍作为别名
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("No XML 'id' specified - using '" + beanName +
                    "' as bean name and " + aliases + " as aliases");
        }
    }

    if (containingBean == null) {
        // 检查beanName和aliases是否在同一个 <beans> 下已经存在
        checkNameUniqueness(beanName, aliases, ele);
    }

    // 2.进一步解析bean的其他所有属性并统一封装至GenericBeanDefinition类型实例中
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                // 3.如果bean定义存在,但是beanName为空,则用Spring默认的生成规则为当前bean生成beanName
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    // Spring提供的生成规则生成beanName,例如:com.joonwhee.open.demo.service.impl.DemoServiceImpl#0
                    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)) {
                        // 如果Spring默认的生成规则生成的beanName为:类名加后缀,则将类名注册为别名
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("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);
        // 4.将bean定义、beanName、bean别名数组封装成BeanDefinitionHolder
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}

1.从第8行到第34行,主要是解析了 id 和 name 属性,其中 name 属性可以通过分割符设置多个。如果 id 存在,则 beanName使用 id,name 属性分割后全部作为别名;如果 id 不存在,则将 name 属性分割后的第1个作为 beanName,剩下的全部作为别名。

下面举个例子:

<!-- 配置1 -->
<bean id="appleService" name="appleOne;appleTwo" class="com.joonwhee.AppleServiceImpl"/>

<!-- 配置2 -->
<bean name="bananaOne;bananaTwo" class="com.joonwhee.BananaServiceImpl"/>

配置1:beanName=appleService,aliases=[appleOne, appleTwo] ;

配置2:beanName=bananaOne,aliases=[bananaTwo]

 

2.进一步解析 bean 的其他所有属性并统一封装至 GenericBeanDefinition 类型实例中,见代码块2详解

3.如果bean定义存在,但是beanName为空,则用Spring默认的生成规则为当前bean生成beanName。

4.将bean定义、beanName、bean别名数组封装成 BeanDefinitionHolder 并返回。

 

代码块2:parseBeanDefinitionElement(ele, beanName, containingBean)

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

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

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

    try {
        String parent = null;
        // 解析parent属性
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }
        // 2.创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);

        // 3.解析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());

        // 4.解析constructor-arg子节点
        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;
}

1.解析了class、parent属性,因为第2步创建 AbstractBeanDefinition 需要用到这两个属性,否则,这两个属性可以放到第3步一起解析。

2.创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition。比较简单,直接 new 一个 GenericBeanDefinition,如果 className 和 classLoader 不为空,则通过反射构建出 BeanClass,并设置为 GenericBeanDefinition 的属性。

3.解析 bean 的剩余属性,见代码块3详解

4.解析 constructor-arg 子节点,见代码块4详解

5.解析 property 子节点,见代码块10详解

 

代码块3:parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
        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) {
        // Take default from containing bean in case of an inner bean definition.
        bd.setScope(containingBean.getScope());
    }

    // 解析abstract属性
    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }

    // 解析lazy-init属性, 默认为false
    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

    // 解析autowire属性
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));

    // 解析dependency-check属性
    String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    bd.setDependencyCheck(getDependencyCheck(dependencyCheck));

    // 解析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 ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(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);
        if (!"".equals(initMethodName)) {
            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;
}

内容比较简单,就是从节点 ele 拿到所有的属性值,塞给 AbstractBeanDefinition 的对应属性。这些属性的使用如下图。

 

代码块4:parseConstructorArgElements(ele, bd)

public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
    // 拿到beanEle节点的所有子节点
    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);
        }
    }
}

拿到 beanEle 节点的所有子节点,遍历解析所有是 constructor-arg 节点的子节点,见代码块5详解。constructor-arg 的使用如下图所示,constructor-arg 节点类似于构造函数,Bean 中必须要有相应的构造函数才可以使用,否则会报错。

 

代码块5:parseConstructorArgElement((Element) node, bd)

public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    // 1.提取基础属性index、type、name属性值
    // 提取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 {
                    // 2.index不为空的处理
                    this.parseState.push(new ConstructorArgumentEntry(index));
                    // 2.1解析ele节点对应的属性值
                    Object value = parsePropertyValue(ele, bd, null);
                    // 2.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
                    ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                    // 2.3将type属性封装到ConstructorArgumentValues.ValueHolder
                    if (StringUtils.hasLength(typeAttr)) {
                        valueHolder.setType(typeAttr);
                    }
                    // 2.4将name属性封装到ConstructorArgumentValues.ValueHolder
                    if (StringUtils.hasLength(nameAttr)) {
                        valueHolder.setName(nameAttr);
                    }
                    valueHolder.setSource(extractSource(ele));
                    // 2.5判断index是否重复指定, 如果是则抛出异常
                    if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                        error("Ambiguous constructor-arg entries for index " + index, ele);
                    }
                    else {
                        // 将index和valueHolder以key-value形式添加至当前BeanDefinition的constructorArgumentValues
                        // 的indexedArgumentValues属性中,(用于上面判断index是否重复指定)
                        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 {
            // 3.index为空的处理
            this.parseState.push(new ConstructorArgumentEntry());
            // 3.1解析ele节点对应的属性值
            Object value = parsePropertyValue(ele, bd, null);
            // 3.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
            ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
            // 3.3将type属性封装到ConstructorArgumentValues.ValueHolder
            if (StringUtils.hasLength(typeAttr)) {
                valueHolder.setType(typeAttr);
            }
            // 3.4将name属性封装到ConstructorArgumentValues.ValueHolder
            if (StringUtils.hasLength(nameAttr)) {
                valueHolder.setName(nameAttr);
            }
            valueHolder.setSource(extractSource(ele));
            // 3.5将valueHolder添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中
            // 与上面的indexedArgumentValues类似,上面有index存为map,这边没index存为list
            bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
        }
        finally {
            this.parseState.pop();
        }
    }
}

1.首先拿到基础属性 index、type、name 的属性值。

2.index不为空的处理:

2.1 首先解析 ele 节点的值,可以看代码块4里的图,每个 constructor-arg 节点必然有一个属性值,可能是通过 value 属性、ref属性、list 属性等。见代码块6详解。

2.5 判断index是否重复指定,如果是则抛出异常;如果不重复,则将 index 和 valueHolder 以 key-value 形式添加至当前BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中(用于前面判断index是否重复指定)。

3.index为空的处理。基本与2相同,不在赘述。

 

代码块6:parsePropertyValue(ele, bd, null)

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

    // Should only have one child element: ref, value, list, etc.
    // 1.拿到ele节点的子节点,例如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) {
                // 只能有1个子节点,否则抛出异常
                error(elementName + " must not contain more than one sub-element", ele);
            }
            else {
                // 找到子节点,赋值给subElement
                subElement = (Element) node;
            }
        }
    }

    // 2.解析constructor-arg上的ref属性
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    // 3.解析constructor-arg上的value属性
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    // 4.合法性校验。在constructor-arg上:ref属性、value属性、子节点,三者只能有1个,因为这三个都是用来表示该节点的值。
    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) {
        // 5.ref属性的处理,使用RuntimeBeanReference封装对应的ref名称(该ref名称指向另一个bean的beanName)
        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) {
        // 6.value属性的处理,使用TypedStringValue封装
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    }
    else if (subElement != null) {
        // 7.解析子节点
        return parsePropertySubElement(subElement, bd);
    }
    else {
        // 8.既没有ref属性,也没有value属性,也没有子节点,没法获取ele节点的值,直接抛异常
        // Neither child element nor "ref" or "value" attribute found.
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

1.拿到 ele 节点的子节点,并赋值给变量 subElement。例如下图中 index=“3” 的节点就有子节点,子节点为 list,其他4个都没有子节点。

7.解析子节点,见代码块7详解。

其他的点见代码中注释。

 

代码块7:parsePropertySubElement(subElement, bd)

public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
    return parsePropertySubElement(ele, bd, null);
}

public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    // 1.校验是否为默认的命名空间,如果不是则走解析自定义节点代码
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    }
    // 2.解析bean节点
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    }
    // 3.解析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 the same XML file.
            refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
            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', 'local' 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;
    }
    // 4.解析idref节点
    else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
        return parseIdRefElement(ele);
    }
    // 5.解析value节点
    else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
        return parseValueElement(ele, defaultValueType);
    }
    // 6.解析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;
    }
    // 7.解析array节点
    else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
        return parseArrayElement(ele, bd);
    }
    // 8.解析list节点
    else if (nodeNameEquals(ele, LIST_ELEMENT)) {
        return parseListElement(ele, bd);
    }
    // 9.解析set节点
    else if (nodeNameEquals(ele, SET_ELEMENT)) {
        return parseSetElement(ele, bd);
    }
    // 10.解析map节点
    else if (nodeNameEquals(ele, MAP_ELEMENT)) {
        return parseMapElement(ele, bd);
    }
    // 11.解析props节点
    else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
        return parsePropsElement(ele);
    }
    else {
        // 12.未知属性,抛异常
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}

1.解析自定义命名空间节点。之后会介绍该内容,本处暂不介绍。

2.解析 bean 节点,之前已经走过该方法,见代码块1详解

5.解析 value 节点,见代码块8详解

8.解析 list 节点,7到11的解析都比较类似,这边拿常用的 list 来介绍。见代码块9详解

 

代码块8:parseValueElement(ele, defaultValueType)

public Object parseValueElement(Element ele, String defaultTypeName) {
    // It's a literal value.
    // 拿到ele节点值
    String value = DomUtils.getTextValue(ele);
    // 拿到ele节点的type属性
    String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE);
    String typeName = specifiedTypeName;
    if (!StringUtils.hasText(typeName)) {
        // ele节点没有type属性则则使用入参defaultTypeName
        typeName = defaultTypeName;
    }
    try {
        // 使用value和type构建TypedStringValue
        TypedStringValue typedValue = buildTypedStringValue(value, typeName);
        typedValue.setSource(extractSource(ele));
        typedValue.setSpecifiedTypeName(specifiedTypeName);
        return typedValue;
    }
    catch (ClassNotFoundException ex) {
        error("Type class [" + typeName + "] not found for <value> element", ele, ex);
        return value;
    }
}

比较简单的方法,拿到 value节点值和 type 属性,利用 value 和 type 构建 TypedStringValue。在14行的 buildTypedStringValue 方法中,如果当前上下文有 classLoader,则会将 type 实例化成对应的 Class,如果type是基本类型,或者 java.lang 包下的常用类,可以直接从缓存(primitiveTypeNameMap、commonClassCache)中获取。

 

代码块9:parseListElement(ele, bd)

public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {
    // 拿到collectionEle节点的value-type,顾名思义,该属性就是该list节点下的value的类型
    String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
    // 拿到collectionEle节点的所有子节点, 一般为<value>
    NodeList nl = collectionEle.getChildNodes();
    // new一个ManagedList,用于存放字节点的值
    ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
    target.setSource(extractSource(collectionEle));
    target.setElementTypeName(defaultElementType);
    target.setMergeEnabled(parseMergeAttribute(collectionEle));
    // 解析子节点集合
    parseCollectionElements(nl, target, bd, defaultElementType);
    return target;
}

protected void parseCollectionElements(
        NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
    // 遍历elementNodes
    for (int i = 0; i < elementNodes.getLength(); i++) {
        Node node = elementNodes.item(i);
        // 跳过description节点
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
            // 调用parsePropertySubElement节点进行解析, 正常list的子节点为<value>节点会直接走到value节点的解析
            // 如果list的子节点还是list,则相当于递归在走到此方法
            target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
        }
    }
}

第25行,会调用 parsePropertySubElement 方法,见代码块7详解。正常情况下,list 里面应该是 value节点(见下图),则会走到代码块8解析出对应的value,然后结束。特殊情况下,可能 list 里面还是 list,则相当于递归在走到此方法。

至此,代码块4 ~ 代码块9 完成了constructor-arg 节点的解析,让我们回到代码块2的第5点,继续解析 property 子节点。

 

代码块10:parsePropertyElements(ele, bd)

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    // 拿到beanEle节点的所有子节点
    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);
        }
    }
}

拿到 beanEle 节点的所有子节点,遍历解析所有是 property 节点的子节点,见代码块11详解。property 的使用如下图所示,property 节点类似于set方法,Bean 中的属性必须要有 set 方法才可以使用,否则会报错。

 

代码块11:parsePropertyElement((Element) node, bd)

public void parsePropertyElement(Element ele, BeanDefinition bd) {
    // 1.拿到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 {
        // 2.校验在相同bean节点下,是否存在相同的name属性,如果存在则抛出异常
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        // 3.解析属性值
        Object val = parsePropertyValue(ele, bd, propertyName);
        // 4.将解析的属性值和属性name封装成PropertyValue
        PropertyValue pv = new PropertyValue(propertyName, val);
        // 5.解析meta节点(基本不用,不深入解析)
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        // 6.将解析出来的PropertyValue,添加到BeanDefinition的propertyValues属性中(上面的重复校验用到)
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
        this.parseState.pop();
    }
}

3.解析属性值,上文已经介绍过该方法,见代码块6详解

 

至此,delegate.parseBeanDefinitionElement(ele) 方法的解析完成,我们可以回到代码块1重新梳理一下思路,我们将 xml 中的bean 配置信息进行了解析,并构建了 AbstractBeanDefinition(GenericBeanDefinition) 对象来存放所有解析出来的属性。最后,我们将 AbstractBeanDefinition 、beanName、aliasesArray 构建成 BeanDefinitionHolder 对象并返回。

而在 parseDefaultElement详解(下)中,我们将对本文解析出来的 BeanDefinitionHolder 信息进行注册。

 

相关文章

Spring IoC:源码学习总览

Spring IoC:refresh前的环境准备

Spring IoC:obtainFreshBeanFactory详解

没有更多推荐了,返回首页