继续上一讲···
为 Bean 配置集合
List, Set 和 Map 是代表 Java 三种主要集合类型的核心接口,而对于每一种集合类型,Java都用不同函数和特性提供了多种可选的实现。在 Spring 中,这些集合类型可以轻松地用一组内建的XML 标记进行配置,例如 <List>、<Set>和 <Map>。
还是以上面的例子为例,但我们把sesametech.springrecipes.s001 复制为sesametech.springrecipes.s002,然后假设我们使用 java.util.List 集合来包含你的后缀,修改后的 SequenceGenerator 类代码片段如下:
packagesesametech.springrecipes.s002;
import java.util.List;
public class SequenceGenerator {
private String prefix;
private List<Object>suffixes;
private int initial;
private int counter;
public SequenceGenerator() {
}
publicSequenceGenerator(Stringprefix, List<Object>suffixes, intinitial) {
this.prefix =prefix;
this.suffixes =suffixes;
this.initial =initial;
}
public synchronized String getSequence(){
StringBufferbuffer = new StringBuffer();
buffer.append(prefix);
buffer.append(initial +counter++);
for (Object suffix : suffixes) {
buffer.append("-");
buffer.append(suffix);
}
return buffer.toString();
}
getter & setter …
}
为了在Bean 配置中定义 java.util.List 接口的属性,必须指定一个包含元素的<list> 标记。<list> 标记中允许的元素可以是有<value> 指定的常量值、<ref> 指定的Bean 应用、<bean> 指定的内部 Bean、<idref> 指定的 ID 引用定义,或者 <null> 指定的空元素,甚至可以嵌入另一个集合。对于本示例的配置,这次我们首先把beans.xml 拷贝到 sesametech.springrecipes.s002 包下,然后修改如下:
<bean
id="sequenceGenerator"
name="sequenceGenerator"
class="sesametech.springrecipes.s002.SequenceGenerator">
<propertyname="prefix"value="30"/>
<propertyname="initial"value="100000"/>
<propertyname="suffixes">
<list>
<value>A</value>
<beanclass="java.net.URL">
<constructor-argvalue="http"/>
<constructor-argvalue="www.sesametech.com"/>
<constructor-argvalue="/"/>
</bean>
<null/>
</list>
</property>
</bean>
接下来,我们修改源码目录“sesametech.springrecipes.s002”包下名为 SequenceGeneratorTest 的测试类,修改后的main() 方法如下所示:
public static void main(String[] args) {
ApplicationContext context =new ClassPathXmlApplicationContext("sesametech/springrecipes/s002/beans.xml");
SequenceGeneratorgenerator = (SequenceGenerator)context.getBean("sequenceGenerator");
System.out.println(generator.getSequence());
System.out.println(generator.getSequence());
}
注意这次我们加载配置文件路径变化,不是在源码根目录下了,而是在sesametech.springrecipes.s002 包下。
在概念上,数组Array 近似于 List,它也是一组排序和索引的集合,可以用索引访问,主要的不同点在于数组的长度是固定的。因此,Bean的属性配置也是通过 <list> 标记实现。
另一个常见的集合类型是java.util.Set。Set 和 List都扩展自统一个接口 java.util.Collection,不同点在于Set 既不排序也不索引,仅能存储独特的对象。为了定义 Set 类型的属性,可通过使用<set> 标记类实现。由于其用法法与 <list> 相同,因此不在举例,给出片段如下:
<set>
<value>A</value>
……
</set>
Map 接口是一个在键值对(key/value)中存储项目的表。你可以通过关键字 key 从 Map 中取得特定的值,关键字和值可以是任何类型。关键字之间是否相等是由 equals() 方法确定。仍然以前面的例子为例,这次我们把包sesametech.springrecipes.s002复制为 sesametech.springrecipes.s003,然后假设我们使用java.util.Map 集合来包含你的后缀,修改后的 SequenceGenerator 代码片段如下:
packagesesametech.springrecipes.s002;
import java.util.List;
public class SequenceGenerator {
private String prefix;
private Map<Object,Object>suffixes;
private int initial;
private int counter;
public SequenceGenerator() {
}
publicSequenceGenerator(Stringprefix, List<Object>suffixes, intinitial) {
this.prefix =prefix;
this.suffixes =suffixes;
this.initial =initial;
}
public synchronized String getSequence(){
StringBufferbuffer = new StringBuffer();
buffer.append(prefix);
buffer.append(initial +counter++);
for (Entry<Object,Object>suffix :suffixes.entrySet()) {
buffer.append("-");
buffer.append(suffix.getKey());
buffer.append("@");
buffer.append(suffix.getValue());
}
return buffer.toString();
}
getter & setter …
}
接下来,修改我们sesametech.springrecipes.s003 包下的 beans.xml 配置文件,片段如下所示:
<bean
id="sequenceGenerator"
name="sequenceGenerator"
class="sesametech.springrecipes.s003.SequenceGenerator">
<propertyname="prefix"value="30"/>
<propertyname="initial"value="100000"/>
<propertyname="suffixes">
<map>
<entrykey="type"value="A"/>
<entrykey="url">
<beanclass="java.net.URL">
<constructor-argvalue="http"/>
<constructor-argvalue="www.sesametech.com"/>
<constructor-argvalue="/"/>
</bean>
</entry>
</map>
</property>
</bean>
接着记得修改一下源码目录“sesametech.springrecipes.s003”包下名为 SequenceGeneratorTest 的测试类的main() 方法中的应用程序上下文的加载路径,如下所示:
ApplicationContext context = new ClassPathXmlApplicationContext("sesametech/springrecipes/s003/beans.xml");
有时候,可能会遇到要为 Map 实例配置一个 null 值的情况,Spring 对此提供了显式支持,例如:
<propertyname="nulledMapValue">
<map>
<entry>
<key> <value>null</value></key>
</entry>
</map>
</property>
java.util.Properties 集合非常近似于 java.util.Map,它也实现 java.util.Map接口,也是存储键值对(key/value)项目。唯一不同的是Properties 集合的键值对始终是字符串。在 Spring 中,可以通过使用<props> 标记来实现,以多个 <prop> 标记作为子项目,而每个<prop> 标记必须定义一个 key 属性并包含对应的属性值。还是以前面的例子为例,这次我们把包sesametech.springrecipes.s003复制为 sesametech.springrecipes.s004,然后假设我们使用java.util.Properties 集合来包含你的后缀,修改后的 SequenceGenerator 代码片段如下:
public class SequenceGenerator {
……
private Properties suffixes;
……
}
接下来,修改我们sesametech.springrecipes.s004 包下的 beans.xml 配置文件,片段如下所示:
<propertyname="suffixes">
<props>
<propkey="type">A</prop>
<propkey="url">http://www.sesametech.com/</prop>
<propkey="null">null</prop>
</props>
</property>
最后不要忘记修改一下源码目录“sesametech.springrecipes.s004”包下名为 SequenceGeneratorTest 的测试类的main() 方法中的应用程序上下文的加载路径,如下所示:
ApplicationContext context = new ClassPathXmlApplicationContext("sesametech/springrecipes/s004/beans.xml");
合并父 Bean 的集合属性
如果你用继承定义 Bean,即为 <bean> 标记添加 parent 属性,那么子 Bean 的集合可以通过添加merge 属性并设置为 true 使其与父 Bean 的集合合并。
对于 List 集合,子 Bean 的集合将附加在父 Bean 的集合之后并保持顺序。以前面的例子为例,我们把包sesametech.springrecipes.s002 复制为sesametech.springrecipes.s005,然后修改我们sesametech.springrecipes.s005 包下的 beans.xml 配置文件,片段如下所示:
<bean
id="baseSequenceGenerator"
class="sesametech.springrecipes.s005.SequenceGenerator">
<property
name="prefix"
value="30" />
<property
name="initial"
value="100000" />
<property name="suffixes">
<list>
<value>A</value>
<value>B</value>
</list>
</property>
</bean>
<bean
id="sequenceGenerator"
parent="baseSequenceGenerator"
class="sesametech.springrecipes.s005.SequenceGenerator">
<property
name="prefix"
value="40" />
<property
name="initial"
value="200000" />
<property name="suffixes">
<list merge="true">
<value>A</value>
<value>C</value>
</list>
</property>
</bean>
记得修改一下源码目录“sesametech.springrecipes.s005”包下名为 SequenceGeneratorTest 的测试类的main() 方法中的应用程序上下文的加载路径,如下所示:
ApplicationContext context = new ClassPathXmlApplicationContext("sesametech/springrecipes/s005/beans.xml");
然后我们运行这个测试类,会发现我们的序列发生器包含了4个后缀:A、B、A 和 C。
对于 Set 或Map 集合,如果有相同的值,子 Bean 的值将覆盖父Bean 的值。例如以下配置后的序列发生器将有 3个后缀:A、B 和 C:
<bean
id="baseSequenceGenerator"
class="sesametech.springrecipes.s003.SequenceGenerator">
<property
name="prefix"
value="30" />
<property
name="initial"
value="100000" />
<property name="suffixes">
<set>
<value>A</value>
<value>B</value>
</set>
</property>
</bean>
<bean
id="sequenceGenerator"
parent="baseSequenceGenerator"
class="sesametech.springrecipes.s003.SequenceGenerator">
<property
name="prefix"
value="40" />
<property
name="initial"
value="200000" />
<property name="suffixes">
<set merge="true">
<value>A</value>
<value>C</value>
</set>
</property>
</bean>
由于不算太难,作为练习,读者可以以包“sesametech.springrecipes.s003”为蓝本,亲自动手试一试。
好了,今天就写到这里了,待续···