2.4.4 设置属性
到目前为止,CDPlayer 和 BlankDisc 类完全是通过构造器注入的,没有使用属性的 Setter 方法。接下来,我们就看一下如何使用 Spring XML 实现属性注入。假设属性注入的 CDPlayer 如下所示:
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
该选择构造器注入还是属性注入呢?作为一个通用的规则,我倾向于对强依赖使用构造器注入,而对可选性的依赖使用属性注入。按照这个规则,我们可以说对于 BlankDisc 来讲,唱片名称、艺术家以及磁道列表是强依赖,因此构造器注入是正确的方案。不过,对于 CDPlayer 来讲,它对 CompactDisc 是强依赖还是可选性依赖可能会有些争议。虽然我不太认同,但你可能会觉得即便没有将 CompactDisc 装入进去,CDPlayer 依然还能具备一些有限的功能。
现在,CDPlayer 没有任何的构造器(除了隐含的默认构造器),它也没有任何的强依赖。因此,你可以采用如下的方式将其声明为 Spring bean:
<bean id="cdPlayer" class="soundsystem.CDPlayer" />
Spring 在创建 bean 的时候不会有任何的问题,但是 CDPlayerTest 会因为出现 NullPointerException 而导致测试失败,因为我们并没有注入 CDPlayer 的 compactDisc 属性。不过,按照如下的方式修改 XML,就能解决该问题:
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<property name="compactDisc" ref="compactDisc" />
</bean>
<property>
元素为属性的 Setter 方法所提供的功能与 <constructor-arg>
元素为构造器所提供的功能是一样的。在本例中,它引用了 ID 为 compactDisc 的 bean(通过 ref 属性),并将其注入到 compactDisc 属性中(通过setCompactDisc() 方法)。如果你现在运行测试的话,它应该就能通过了。
我们已经知道,Spring 为 <constructor-arg>
元素提供了 c-
命名空间作为替代方案,与之类似,Spring 提供了更加简洁的 p-
命名空间,作为 <property>
元素的替代方案。为了启用 p-
命名空间,必须要在 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"
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-
命名空间,按照以下的方式装配 compactDisc 属性:
<bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="compactDisc" />
p-
命名空间中属性所遵循的命名约定与 c-
命名空间中的属性类似。图 2.2阐述了 p-
命名空间属性是如何组成的。

首先,属性的名字使用了 p:
前缀,表明我们所设置的是一个属性。接下来就是要注入的属性名。最后,属性的名称以 -ref
结尾,这会提示 Spring 要进行装配的是引用,而不是字面量。
将字面量注入到属性中
属性也可以注入字面量,这与构造器参数非常类似。作为示例,我们重新看一下 BlankDisc bean。不过,BlankDisc 这次完全通过属性注入进行配置,而不是构造器注入。新的 BlankDisc 类如下所示:
package soundsystem;
import java.util.List;
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("Playing " + title + " by " + artist);
for (String track : tracks) {
System.out.println("-Track: " + track);
}
}
}
现在,它不再强制要求我们装配任何的属性。你可以按照如下的方式创建一个 BlankDiscbean,它的所有属性全都是空的:
<bean id="reallyBlankDisc" class="soundsystem.BlankDisc" />
当然,如果在装配 bean 的时候不设置这些属性,那么在运行期 CD 播放器将不能正常播放内容。play() 方法可能会遇到的输出内容是 “Playing null by null”,随之会抛出 NullPointerException 异常,这是因为我们没有指定任何的磁道。所以,我们需要装配这些属性,可以借助 <property>
元素的 value 属性实现该功能:
<bean id="compactDisc" class="soundsystem.BlankDisc">
<property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
<property name="artist" value="The Beatles">
<property name="tracks">
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</list>
</property>
</bean>
在这里,除了使用 <property>
元素的 value 属性来设置 title 和 artist,我们还使用了内嵌的 <list>
元素来设置 tracks 属性,这与之前通过 <constructor-arg>
装配 tracks 是完全一样的。
另外一种可选方案就是使用 p-
命名空间的属性来完成该功能:
<bean id="compactDisc" class="soundsystem.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles" >
<property name="tracks">
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</list>
</property>
</bean>
与 c-
命名空间一样,装配 bean 引用与装配字面量的唯一区别在于是否带有 -ref
后缀。如果没有 -ref
后缀的话,所装配的就是字面量。
但需要注意的是,我们不能使用 p-
命名空间来装配集合,没有便利的方式使用 p-
命名空间来指定一个值(或 bean 引用)的列表。但是,我们可以使用 Spring util-
命名空间中的一些功能来简化 BlankDisc bean。
首先,需要在 XML 中声明 util-
命名空间及其模式:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
...
</beans>
util-
命名空间所提供的功能之一就是元素,它会创建一个列表的 bean。借助,我们可以将磁道列表转移到 BlankDisc bean 之外,并将其声明到单独的 bean 之中,如下所示:
<util:list id="trackList">
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</util:list>
现在,我们能够像使用其他的 bean 那样,将磁道列表 bean 注入到 BlankDisc bean 的 tracks 属性中:
<bean id="compactDisc" class="soundsystem.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles"
p:tracks-ref="trackList" />
<util:list>
只是 util-
命名空间中的多个元素之一。表 2.1 列出了 util-
命名空间提供的所有元素。
在需要的时候,你可能会用到 util-
命名空间中的部分成员。但现在,在结束本章前,我们看一下如何将自动化配置、JavaConfig 以及 XML 配置混合并匹配在一起。
元素
描述
<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,其中包含值或引用
Last updated
Was this helpful?