7.5.8 注入集合值

7.5.8 注入集合值

如果需要调用形参类型为集合的setter方法,或调用形参类型为集合的构造器,则可使用集合元素<list><set><map><props>分别来设置类型为ListSetMapProperties的集合参数值。
下面先定义一个包含大量集合属性的Java类,配置文件将会通过上面那些元素来为这些集合属性设置属性值。看如下Java类的代码。

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\collection
└─src\
├─beans.xml
├─lee\
│ └─BeanTest.java
└─org\
└─crazyit\
└─app\
└─service\
├─Axe.java
├─impl\
│ ├─Chinese.java
│ ├─SteelAxe.java
│ └─StoneAxe.java
└─Person.java

Chinese.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package org.crazyit.app.service.impl;

import java.util.*;

import org.crazyit.app.service.*;

public class Chinese implements Person
{
// 下面是系列集合类型的成员变量
private List<String> schools;
private Map scores;
private Map<String , Axe> phaseAxes;
private Properties health;
private Set axes;
private String[] books;

public Chinese()
{
System.out.println("Spring实例化主调bean:Chinese实例...");
}

// schools的setter方法
public void setSchools(List schools)
{
this.schools = schools;
}
// scores的setter方法
public void setScores(Map scores)
{
this.scores = scores;
}
// phaseAxes的setter方法
public void setPhaseAxes(Map<String , Axe> phaseAxes)
{
this.phaseAxes = phaseAxes;
}
// health的setter方法
public void setHealth(Properties health)
{
this.health = health;
}
// axes的setter方法
public void setAxes(Set axes)
{
this.axes = axes;
}
// books的setter方法
public void setBooks(String[] books)
{
this.books = books;
}

// 访问上面全部的集合类型的成员变量
public void test()
{
System.out.println(schools);
System.out.println(scores);
System.out.println(phaseAxes);
System.out.println(health);
System.out.println(axes);
System.out.println(java.util.Arrays.toString(books));
}
}

在上面的Chinese类中定义了6个集合类型的成员变量。下面分别为<property>元素增加<list><set><map><props>子元素来配置这些集合类型的参数值。
下面是Spring的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义2个普通Axe Bean -->
<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>
<bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/>
<!-- 定义chinese Bean -->
<bean id="chinese" class="org.crazyit.app.service.impl.Chinese">
<property name="schools">
<!-- 为调用setSchools()方法配置List集合作为参数值 -->
<list>
<!-- 每个value、ref、bean...都配置一个List元素 -->
<value>小学</value>
<value>中学</value>
<value>大学</value>
</list>
</property>
<property name="scores">
<!-- 为调用setScores()方法配置Map集合作为参数值 -->
<map>
<!-- 每个entry配置一个key-value对 -->
<entry key="数学" value="87"/>
<entry key="英语" value="89"/>
<entry key="语文" value="82"/>
</map>
</property>
<property name="phaseAxes">
<!-- 为调用setPhaseAxes()方法配置Map集合作为参数值 -->
<map>
<!-- 每个entry配置一个key-value对 -->
<entry key="原始社会" value-ref="stoneAxe"/>
<entry key="农业社会" value-ref="steelAxe"/>
</map>
</property>
<property name="health">
<!-- 为调用setHealth()方法配置Properties集合作为参数值 -->
<props>
<!-- 每个prop元素配置一个属性项,其中key指定属性名 -->
<prop key="血压">正常</prop>
<prop key="身高">175</prop>
</props>
<!--
<value>
pressure=normal
height=175
</value> -->
</property>
<property name="axes">
<!-- 为调用setAxes()方法配置Set集合作为参数值 -->
<set>
<!-- 每个value、ref、bean..都配置一个Set元素 -->
<value>普通的字符串</value>
<bean class="org.crazyit.app.service.impl.SteelAxe"/>
<ref bean="stoneAxe"/>
<!-- 为Set集合配置一个List集合作为元素 -->
<list>
<value>20</value>
<!-- 再次为List集合配置一个Set集合作为元素 -->
<set>
<value type="int">30</value>
</set>
</list>
</set>
</property>
<property name="books">
<!-- 为调用setBooks()方法配置数组作为参数值 -->
<list>
<!-- 每个value、ref、bean...都配置一个数组元素 -->
<value>疯狂Java讲义</value>
<value>疯狂Android讲义</value>
<value>轻量级Java EE企业应用实战</value>
</list>
</property>
</bean>
</beans>

上面的代码是配置集合类型的参数值的关键代码,从配置文件可以看出, SpringList集合和数组的处理是一样的,都用<list>元素来配置
当使用<list><set><map>.等元素配置集合类型的参数值时,还需要配置集合元素。由于集合元素又可以是基本类型值、引用容器中的其他Bean、嵌套Bean或集合属性等,所以<list><key><set>元素又可接受如下子元素:

  • <value>:指定集合元素是基本数据类型值或字符串类型值。
  • <ref>:指定集合元素是容器中的另一个Bean实例。
  • <bean>:指定集合元素是一个嵌套Bean
  • <list><set><map><props>:指定集合元素又是集合。

props元素说明

<props>元素用于配置Properties类型的参数值, Properties类型是一种特殊的类型,其keyvalue能是字符串,故Spring配置Properties类型的参数值比较简单:每个key-value对只要分别给出keyvalue就足够了;因为keyvalue都是字符串类型,所以使用如下格式的<prop>元素就够了:

1
2
3
4
<props>
<prop key="血压">正常</prop>
<prop key="身高">175</prop>
</props>

简化写法

Spring还提供了一个简化语法来支持Properties形参的setter方法,例如如下配置片段:

1
2
3
4
5
6
<property name="health">
<value>
pressure=normal
height=175
</value>
</property>

简化写法中不能出现中文

上面这种配置方式同样配置了两组属性,但这种配置语法有一个很大的限制:属性名、属性值都只能是英文或数字,不可出现中文!

map元素说明

当使用<map>元素配置Map参数值时比较复杂,因为Map集合的每个元素由keyvalue两个部分组成,所以配置文件中的每个<entry>配置一组key-value对,其中<entry>元素支持如下4个属性。

<entry>元素的属性 描述
key 如果Map key是基本类型值或字符串,则可使用该属性来指定Map key
key-ref 如果Map key是容器中的另一个Bean实例,则可使用该属性指定容器中其他Beanid
value 如果Map value是基本类型值或字符串,则可使用该属性来指定Map value;
value-ref 如果Map value是容器中的另一个Bean实例,则可使用该属性指定容器中其他Beanid

由于Map集合的keyvalue都可以是基本类型值引用容器中的其他Bean、嵌套Bean或集合属性等,所以也可以采用比较传统、比较臃肿的写法。例如,将上面关于scores属性的配置写成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<property name="scores">
<map>
<entry>
<key>
<value>数学</value>
</key>
<value>87</value>
</entry>
<entry>
<key>
<value>英语</value>
</key>
<value>89</value>
</entry>
<entry>
<key>
<value>语文</value>
</key>
<value>82</value>
</entry>
</map>
</property>

从上面配置可以看出,<key>元素专门用于配置Map集合的key-value对的key,又由于Map key又可能是基本类型、引用容器中已有的Bean、嵌套Bean、集合等,因此<key>的子元素又可以是valuerefbeanlistsetmapprops等元素。

集合的合并

Spring2.0开始, Spring loC容器将支持集合的合并,子Bean中的集合属性值可以从其父Bean的集合属性继承覆盖而来。也就是说,Bean的集合属性的最终值是父Bean、子Bean合并后的最终结果,而且子Bean集合中的元素可以覆盖父Bean集合中对应的元素
下面的配置片段示范了集合合并的特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<beans>
<bean id=""parent abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@crazyit.org</prop>
<prop key="suppport">suppport@crazyit.org</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property id="child" name="adminEmails">
<props merge="true">
<prop key="sales">sales@crazyit.org</prop>
<prop key="support">support@crazyit.org</prop>
</props>
<property>
</bean>
</beans>

上面的配置片段中child Bean继承了parent Bean,并为<props>元素指定了merge="true",这将会把parent Bean的集合属性合并到child Bean中;
当进行合并时,由child Bean再次配置了名为support的属性,所以该属性将会覆盖parent Bean中的配置定义,于是child beanadminEmails属性值如下:

1
2
3
administrator=administratore@crazyit.org
sales=sales@crazyit.org
support=master@crazyit.org

泛型支持

JDK1.5以后,Java可以使用泛型指定集合元素的类型,则Spring可通过反射来获取集合元素的类型,这样Spring的类型转换器也会起作用了。
例如如下Java代码:

1
2
3
4
5
6
7
8
public class Test
{
private Map<string, Double> prices;
public void setPrices(Map<string Double> prices)
{
this.prices= prices;
}
}

上面的prices集合是Map集合,且程序使用泛型限制了MapkeyString,且valueDouble,则Spring可根据泛型信息把配置文件的集合参数值转换成相应的数据类型。例如如下配置片段:

1
2
3
4
5
6
7
8
<bean id="test" class="lee.Test">
<property name="prices">
<map>
<entry key="疯狂 Android讲义" vaue="99.0"/>
<entry key="疯狂Java讲义" value="109.0"/>
</map>
</property>
</bean>