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

来源:互联网 发布:mac怎么登陆千牛 编辑:程序博客网 时间:2024/05/16 16:18

一、基本使用

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;        }    }
0 0