spring源码附录(5)解析子元素constructor-arg

一、基本使用

public class Animal {

    public String type;

    public int age;

    /**
     * @param type
     * @param age
     */
    public Animal(String type, int age) {
        super();
        this.type = type;
        this.age = age;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Animal [type=" + type + ", age=" + age + "]";
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="animal" class="test.constructor.Animal">
        <constructor-arg index="0" value="cat" type="String"></constructor-arg>
        <constructor-arg value="100" ></constructor-arg>
    </bean>
</beans>
public class Main {

    public static String XML_PATH = "test\\constructor\\applicationContxt.xml";

    public static void main(String[] args) {
        try {
            Resource resource = new ClassPathResource(XML_PATH);
            XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
            Animal bean = (Animal) beanFactory.getBean("animal");
            System.out.println(bean);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

二、spring解析

对于construction-arg 子元素的解析,Spring 是通过 BeanDefinitionParserDelegate. parseConstructorArgElements(Element beanEle, BeanDefinition bd); 方法来实现的

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

追踪下去如下:

从上面的代码上看,对构造函数中属性的解析,经历了以下几个过程:

  1. 略过description 和 meta

  2. 提取 ref ,value 属性,并验证其合法性,

  3. ref 属性的处理,使用 RuntimeBeanReference 封装

  4. Value 属性的处理 , 使用TypedStringValue封装

  5. 子属性的处理 如

<constructor-arg>
  <map>
   <entry key = "key" value = "value"></entry>
     </map>
</constructor-arg>

而对于子元素,则交给 parsePropertySubElement 方法来实现对各种子元素进行分类处理

public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
        return parsePropertySubElement(ele, bd, null);
}
/**
     * Parse a value, ref or collection sub-element of a property or constructor-arg
     * element.
     * 
     * @param ele subelement of property element; we don't know which yet
     * @param defaultValueType the default type (class name) for any {@code &lt;value&gt;}
     *        tag that might be created
     */
    public Object parsePropertySubElement(Element ele, BeanDefinition bd,
            String defaultValueType) {
        if (!isDefaultNamespace(ele)) {
            return parseNestedCustomElement(ele, bd);
        }
        else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
            BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
            if (nestedBd != null) {
                nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
            }
            return nestedBd;
        }
        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;
        }
        // 对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;
        }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值