3.7 spring-property 子元素的使用与解析

1.0 Property子元素的使用

  property 子元素是再常用不过的了, 在看Spring源码之前,我们先看看它的使用方法,

1. 实例类如下:

 1 public class Animal {
 2 
 3     public String type;
 4 
 5     public Set<Integer> age;
 6 
 7     private Map<String, Integer> sell;
 8 
 9     public Animal() {
10 
11     }
12 
13     /**
14      * @return the type
15      */
16     public String getType() {
17         return type;
18     }
19 
20     /**
21      * @param type the type to set
22      */
23     public void setType(String type) {
24         this.type = type;
25     }
26 
27     /**
28      * @return the age
29      */
30     public Set<Integer> getAge() {
31         return age;
32     }
33 
34     /**
35      * @param age the age to set
36      */
37     public void setAge(Set<Integer> age) {
38         this.age = age;
39     }
40 
41     /**
42      * @return the sell
43      */
44     public Map<String, Integer> getSell() {
45         return sell;
46     }
47 
48     /**
49      * @param sell the sell to set
50      */
51     public void setSell(Map<String, Integer> sell) {
52         this.sell = sell;
53     }
54 
55     /*
56      * (non-Javadoc)
57      * 
58      * @see java.lang.Object#toString()
59      */
60     @Override
61     public String toString() {
62         return "Animal [type=" + type + ", age=" + age + ", sell=" + sell + "]";
63     }
64 
65 }

xml如下,

<?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.property.Animal">
        <property name="type" value="cat"></property>
        <property name="age">
            <set>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </set>
        </property>
        <property name="sell">
            <map>
                <entry key="blue" value="111"></entry>
                <entry key="red" value="22"></entry>
            </map>
        </property>
    </bean>
</beans> 

测试类如下:

 1 public class Main {
 2 
 3     public static String XML_PATH = "test\property\applicationContxt.xml";
 4 
 5     public static void main(String[] args) {
 6         try {
 7             Resource resource = new ClassPathResource(XML_PATH);
 8             XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
 9             Animal bean = (Animal) beanFactory.getBean("animal");
10             System.out.println(bean);
11         }
12         catch (Exception e) {
13             e.printStackTrace();
14         }
15     }
16 }

控制台输出的结果为

Animal [type=cat, age=[1, 2, 3], sell={blue=111, red=22}]

2.0 Spring具体的解析过程为:

  2.1 

 1 /**
 2      * Parse property sub-elements of the given bean element.
 3      */
 4     public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
 5         NodeList nl = beanEle.getChildNodes();
 6         for (int i = 0; i < nl.getLength(); i++) {
 7             Node node = nl.item(i);
 8             if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
 9                 // 这里进去
10                 parsePropertyElement((Element) node, bd);
11             }
12         }
13     }

  2.2 

 1 /**
 2      * Parse a property element.
 3      */
 4     public void parsePropertyElement(Element ele, BeanDefinition bd) {
 5         // 获取配置文件中name 的值
 6         String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
 7         if (!StringUtils.hasLength(propertyName)) {
 8             error("Tag 'property' must have a 'name' attribute", ele);
 9             return;
10         }
11         this.parseState.push(new PropertyEntry(propertyName));
12         try {
13             // 不容许多次对同一属性配置
14             if (bd.getPropertyValues().contains(propertyName)) {
15                 error("Multiple 'property' definitions for property '" + propertyName
16                         + "'", ele);
17                 return;
18             }
19             Object val = parsePropertyValue(ele, bd, propertyName);
20             PropertyValue pv = new PropertyValue(propertyName, val);
21             parseMetaElements(ele, pv);
22             pv.setSource(extractSource(ele));
23             bd.getPropertyValues().addPropertyValue(pv);
24         }
25         finally {
26             this.parseState.pop();
27         }
28     }

  2.3 然后又回到parsePropertyValue 方法了

 1 public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
 2         String elementName = (propertyName != null) ? "<property> element for property '"
 3                 + propertyName + "'" : "<constructor-arg> element";
 4 
 5         // Should only have one child element: ref, value, list, etc.
 6         // 应该只有一个子元素:REF,值,列表等。
 7         NodeList nl = ele.getChildNodes();
 8         Element subElement = null;
 9         for (int i = 0; i < nl.getLength(); i++) {
10             Node node = nl.item(i);
11             // 对应的description 或者meta不处理
12             if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)
13                     && !nodeNameEquals(node, META_ELEMENT)) {
14                 // Child element is what we're looking for.
15                 if (subElement != null) {
16                     error(elementName + " must not contain more than one sub-element",
17                             ele);
18                 }
19                 else {
20                     subElement = (Element) node;
21                 }
22             }
23         }
24         // 解析 ref
25         boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
26         // 解析 value
27         boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
28         if ((hasRefAttribute && hasValueAttribute)
29                 || ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
30             /*
31              * 1.不能同时有ref 又有 value 2.不能存在ref 或者 value 又有子元素
32              */
33             error(elementName
34                     + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element",
35                     ele);
36         }
37 
38         if (hasRefAttribute) {
39             String refName = ele.getAttribute(REF_ATTRIBUTE);
40             if (!StringUtils.hasText(refName)) {
41                 error(elementName + " contains empty 'ref' attribute", ele);
42             }
43             // ref 属性的处理 , 使用RuntimeBeanReference封装对应的ref名称
44             RuntimeBeanReference ref = new RuntimeBeanReference(refName);
45             ref.setSource(extractSource(ele));
46             return ref;
47         }
48         else if (hasValueAttribute) {
49             // Value 属性的处理 , 使用TypedStringValue封装对应的
50             TypedStringValue valueHolder = new TypedStringValue(
51                     ele.getAttribute(VALUE_ATTRIBUTE));
52             valueHolder.setSource(extractSource(ele));
53             return valueHolder;
54         }
55         else if (subElement != null) {
56             // 解析子元素
57             return parsePropertySubElement(subElement, bd);
58         }
59         else {
60             // Neither child element nor "ref" or "value" attribute found.
61             // 对于没有ref 也没有子元素的,Spring只好丢出异常
62             error(elementName + " must specify a ref or value", ele);
63             return null;
64         }
65     }

这里之前构造函数的解析那里已经讲得很详细了,这里不多做解释,不同的是返回值使用PropertyValue 封装,并且记录在BeanDefinition 的 propertyValues属性当中.

原文地址:https://www.cnblogs.com/mjorcen/p/3647847.html