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属性当中.