Spring 学习笔记之通过 XML 装配 Bean 的一些细节

一、c 命名空间

通过构造器注入 Bean 的时候通常需要使用到元素,作为替代的方案,可以使用 Spring 的 c - 命名空间。c - 命名空间是在 Spring 3.0 中加入的,它是在 XML 中更为简洁地描述构造器参数的方式。要使用 c - 命名空间,必须要在 XML 的顶部声明其模式,如下所示:

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

在 c - 命名空间和模式声明后,就可以使用它来声明构造器参数了,如下所示:

1
2
3
4
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.Transfer"></bean>

<bean id="cdPlayer" class="cn.javacodes.spring.beans.soundsystem.CDPlayer"
c:cd-ref="compactDisc" />

可以看到上面的方式也有一些问题,c:cd-ref 中的 cd 即为构造器参数的名称,这种方式对于后期代码的重构是非常不友好的,那么为了解决这个问题,可以使用参数的索引来替代参数名称,如下所示:

1
2
3
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.Transfer"></bean>
<bean id="cdPlayer" class="cn.javacodes.spring.beans.soundsystem.CDPlayer"
c:_0-ref="compactDisc" />

当然如果构造器只有一个参数,可以连索引一起略去:

1
2
3
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.Transfer"></bean>
<bean id="cdPlayer" class="cn.javacodes.spring.beans.soundsystem.CDPlayer"
c:_-ref="compactDisc" />

不过在我的测试中,这种方式在 idea 中会报错。

二、装配集合

(一)装配 List 和 Set

BlankDisc 类的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package cn.javacodes.spring.beans.soundsystem.collections;
import cn.javacodes.spring.beans.soundsystem.CompactDisc;
import java.util.List;
/**
* Created by Eric on 2016/10/16.
*/
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
public void play() {
System.out.println("正在播放" + artist + "的专辑:" + title);
for (String track : tracks) {
System.out.println("-Track:" + track);
}
}
}

在 Spring 中配置这个类的 bean 时需要提供一个 list,当然,你可以给它传递为空值:

1
2
3
4
5
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.collections.BlankDisc">
<constructor-arg value="Transfer"></constructor-arg>
<constructor-arg value="周传雄/小刚"></constructor-arg>
<constructor-arg><null/></constructor-arg>
</bean>

不过如果传递 null 的话,当调用 play () 方法时,必然会产生 NullPointerException 异常,通常情况下,我们更多的给它装配一个 List。

我们有很多种解决方案,首先,可以使用元素将其声明为一个列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.collections.BlankDisc">
<constructor-arg value="Transfer"></constructor-arg>
<constructor-arg value="周传雄/小刚"></constructor-arg>
<constructor-arg>
<list>
<value>忘记</value>
<value>出卖</value>
<value>寂寞轰炸</value>
<value>游戏爱情</value>
<value>心结</value>
<value>记事本</value>
<value>啤酒泡泡</value>
<value>黄昏</value>
<value>末班车</value>
<value>心血来潮</value>
<value>时间</value>
</list>
</constructor-arg>
</bean>

当然,也可以使用来替代达到引用其它 bean 的目的,再次不做赘述。

在我们的例子中构造器参数类型为 List,因此使用元素进行注入是合情合理的,尽管如此,我们仍然可以使用元素来进行注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.collections.BlankDisc">
<constructor-arg value="Transfer"></constructor-arg>
<constructor-arg value="周传雄/小刚"></constructor-arg>
<constructor-arg>
<set>
<value>忘记</value>
<value>出卖</value>
<value>寂寞轰炸</value>
<value>游戏爱情</value>
<value>心结</value>
<value>记事本</value>
<value>啤酒泡泡</value>
<value>黄昏</value>
<value>末班车</value>
<value>心血来潮</value>
<value>时间</value>
</set>
</constructor-arg>
</bean>

元素的区别并不大,其中最重要的区别在于 Spring 创建要装配的集合时,所创建的是 Set 还是 List。如果是 Set 的话,所有重复的值都会被忽略掉,并且存放的顺序也不会得到保证,这个相信大家对 Set 和 List 的区别都有明确的认识。不过无论哪种情况下,都可以用来装配 List、Set 甚至数组。

(二)、装配 Map

我们将上面的 BlankDisc 稍作改动,将原有的 List 改为 Map:

1
2
3
4
5
6
7
8
private String title;
private String artist;
private Map<String,String> tracks;
public BlankDisc(String title, String artist, Map<String, String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}

装配 Map 的方式如下:

1
2
3
4
5
6
7
8
9
10
11
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.collections.BlankDisc">
<constructor-arg value="Transfer"></constructor-arg>
<constructor-arg value="周传雄/小刚"></constructor-arg>
<constructor-arg>
<map>
<entry key="忘记" value="5:12"/>
<entry key="出卖" value="4:54"/>
<entry ……
</map>
</constructor-arg>
</bean>

当然元素可以分别用元素替代用于引用其它 Bean。

(三)、装配 Properties

Properties 与 Map 非常类似,不过区别主要在于 Map 的 key 和 Value 可以是任意类型的对象,而 Properties 要求 key 和 value 必须都是 String 类型,而很多场景下我们的 key 和 value 的确都是 String 类型,比如数据库连接信息的配置。

为了演示 Properties 的相关配置,我们创建一个类 DataSource:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package cn.javacodes.spring.beans.properties;
import java.util.Properties;
/**
* Created by Eric on 2016/10/16.
*/
public class DataSource {

private Properties properties;
public DataSource(Properties properties) {
this.properties = properties;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}

在 Spring XML 配置如下:

1
2
3
4
5
6
7
8
9
10
<bean id="dataSource" class="cn.javacodes.spring.beans.properties.DataSource">
<constructor-arg>
<props>
<prop key="user">root</prop>
<prop key="password">123456</prop>
<prop key="url">jdbc:mysql:///test</prop>
<prop key="driver">com.mysql.jdbc.Driver</prop>
</props>
</constructor-arg>
</bean>

三、p 命名空间

我们知道配置 bean 的属性时需要使用元素,为了简化这种方式,与 c 命名空间一样,Spring 为我们提供了 p 命名空间。为了使用 p - 命名空间,必须在 xml 顶部进行声明:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
……
</beans>

然后就可以使用 p - 命名空间了,使用方法如下:

1
2
<bean id="cdPlayer" class="cn.javacodes.spring.beans.soundsystem.CDPlayer"
p:cd-ref="compactDisc"/>

属性的名称以 - ref 结尾的,代表 Spring 要进行装配的是 bean 的引用而不是字面值(String)。

四、util 命名空间

p - 命名空间和 c - 命名空间都不能对集合类型进行装配,不过我们可以使用 util 命名空间来简化对集合的装配,声明如下:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

现在就可以使用 util 命名空间了,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
<util:list id="trackList">
<value>忘记</value>
<value>出卖</value>
<value>寂寞轰炸</value>
<value>游戏爱情</value>
<value>心结</value>
<value>记事本</value>
<value>啤酒泡泡</value>
<value>黄昏</value>
<value>末班车</value>
<value>心血来潮</value>
<value>时间</value>
</util:list>

然后就可以像引用其它 Bean 一样将 list 轻松引用,如下所示:

1
2
<bean id="compactDisc" class="cn.javacodes.spring.beans.soundsystem.collections.BlankDisc"
c:title="Transfer" c:artist="周传雄/小刚" c:tracks-ref="trackList"/>

util:list 只是 util - 命名空间提供的众多元素之一,下表列出了 util - 命名空间提供的所有元素:

元素 描述
util:constant 引用某个类型的 public static 域,并墙漆暴露为 bean
util:list 创建一个 java.util.List 类型的 bean,其中包含值或引用
util:map 创建一个 java.util.Map 类型的 bean,其中包含值或引用
util:properties 创建一个 java.util.Properties 类型的 bean
util:property-path 引用一个 bean 的属性(或内嵌属性),并将其暴露为 bean
util:set 创建一个 java.util.set 类型的 bean,其中包含值或引用