Spring源码学习【三】填坑篇之BeanDefinition的解析

在  Spring源码学习【二】IOC容器的初始化(二)BeanDefinition载入 中,我们分析了BeanDefinition的载入过程,同时也留下了这样一句注释:

// TODO:待深入学习
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, con-tainingBean);

下面来填上这里挖下的坑,这句代码实际上是将XML的Element元素解析为具体BeanDefinition的入口,让我们回到BeanDefinitionParserDelegate类的这个方法中,代码如下:

public class BeanDefinitionParserDelegate {

    ...

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

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

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

        try {
            // 创建一个具体的BeanDefinition
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 解析BeanDefinition属性
            // 比如:singleton、scope、abstract、lazy-init、autowire等
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            // 解析<meta/>元素
            parseMetaElements(ele, bd);
            // 解析<lookup-method/>元素
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            // 解析<replace-method/>元素
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            // 解析<contructor-args/>元素
            parseConstructorArgElements(ele, bd);
            // 重点关注一下解析<property/>元素
            parsePropertyElements(ele, bd);
            // 解析<qualifier/>元素
            parseQualifierElements(ele, bd);

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

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

        return null;
    }

}

在上面的代码中可以看到,创建了一个BeanDefinition,然后根据XML资源中的配置解析相关的属性配置,并设置到BeanDefinition,这里理解起来是比较简单的,我们需要重点关注parsePropertyElements这个方法,这个方法中实现了解析<bean>元素下的<property>元素,代码如下:

public class BeanDefinitionParserDelegate {

    ...

    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
        // 获得bean元素下的子节点
        NodeList nl = beanEle.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            // 解析property属性
            if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
                parsePropertyElement((Element) node, bd);
            }
        }
    }

    public void parsePropertyElement(Element ele, BeanDefinition bd) {
        ...
        // 重点关注这里
        Object val = parsePropertyValue(ele, bd, propertyName);
        PropertyValue pv = new PropertyValue(propertyName, val);
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        // 将解析后的property添加到BeanDefinition中
        bd.getPropertyValues().addPropertyValue(pv);
        ...
    }

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

        // <property>下仅允许一个子元素
        NodeList nl = ele.getChildNodes();
        Element subElement = null;
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) {
                // Child element is what we're looking for.
                if (subElement != null) {
                    error(elementName + " must not contain more than one sub-element", ele);
                }
                else {
                    subElement = (Element) node;
                }
            }
        }

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

        // 有ref属性,即引用其他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属性,即普通字符串
        else if (hasValueAttribute) {
            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
            valueHolder.setSource(extractSource(ele));
            return valueHolder;
        }
        // 有子元素标签,如<list>、<array>等
        else if (subElement != null) {
            return parsePropertySubElement(subElement, bd);
        }
        else {
            error(elementName + " must specify a ref or value", ele);
            return null;
        }
    }

    @Nullable
    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;
        }
        // bean引用
        else if (nodeNameEquals(ele, REF_ELEMENT)) {
            String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
            boolean toParent = false;
            if (!StringUtils.hasLength(refName)) {
                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;
        }
        // id引用
        else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
            return parseIdRefElement(ele);
        }
        // 普通字符串
        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;
        }
        // 数组
        else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
            return parseArrayElement(ele, bd);
        }
        // 列表
        else if (nodeNameEquals(ele, LIST_ELEMENT)) {
            return parseListElement(ele, bd);
        }
        // 集合
        else if (nodeNameEquals(ele, SET_ELEMENT)) {
            return parseSetElement(ele, bd);
        }
        // Map
        else if (nodeNameEquals(ele, MAP_ELEMENT)) {
            return parseMapElement(ele, bd);
        }
        else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
            return parsePropsElement(ele);
        }
        else {
            error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
            return null;
        }
    }

}

最终,解析处理落在了parseXXElement方法上,这一系列方法实现了对各种元素的解析,我们以集合元素的解析为例看一看具体的解析方式,代码如下:

public class BeanDefinitionParserDelegate {

    ...

    /**
     * 解析Array元素
     */
    public Object parseArrayElement(Element arrayEle, @Nullable BeanDefinition bd) {
        String elementType = arrayEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
        NodeList nl = arrayEle.getChildNodes();
        ManagedArray target = new ManagedArray(elementType, nl.getLength());
        target.setSource(extractSource(arrayEle));
        target.setElementTypeName(elementType);
        target.setMergeEnabled(parseMergeAttribute(arrayEle));
        parseCollectionElements(nl, target, bd, elementType);
        return target;
    }

    /**
     * 解析List元素
     */
    public List<Object> parseListElement(Element collectionEle, @Nullable BeanDefinition bd) {
        String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
        NodeList nl = collectionEle.getChildNodes();
        ManagedList<Object> target = new ManagedList<>(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, @Nullable BeanDefinition bd, String defaultElementType) {
        for (int i = 0; i < elementNodes.getLength(); i++) {
            Node node = elementNodes.item(i);
            // 这里会解析子元素,比如我们list的子元素是value,那么最终会添加一个字符串到集合中
            if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
                target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
            }
        }
    }

}

到这里,我们发现最终将集合property解析为ManagedXXX对象,并将其添加到了BeanDefinition中。这里的ManagedXXX是对集合类的进一步封装,我们可以参照ManagedArray的类继承图,如下所示:

OK,到这里BeanDefinition的解析就简略分析完了,最终在BeanDefinition以ManagedXXX对象存在的各个Property将会在依赖注入的过程中继续发挥作用

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值