[Spring实战系列](9)装配集合

前两篇文章中,我们已经了解了如何使用Spring 配置简单属性值(使用value 属性)和引用其他Bean 的属性(使用ref 属性)。但是value 和ref 仅在Bean 的属性值是单个值的情况下才有用。当Bean 的属性值是集合,Spring
该如何配置呢?

当配置集合类型的Bean属性时,Spring 提供了4 种类型的集合配置元素。

集合元素 用途
<list> 装配list类型的值,允许重复。
<set> 装配set类型的值,不允许重复。
<map> 装配map类型的值,名称和值可以使任意类型。
<props> 装配properties类型的值,名称和值必须都是String类型。

当装配类型为数组或者java.util.Collection 任意实现的属性时,<list>和<set> 元素非常有用。我们很快就会看到,其实属性实际定义的集合类型与选择<list> 或者<set> 元素没有任何关系。如果属性为任意的java.util.Collection类型时,这两个配置元素在使用时几乎可以完全互换。

<map> 和<props> 这两个元素分别对应java.util.Map 和java.util.Properties。当我们需要由键-
值对组成的集合时,这两种配置元素非常有用。关键区别在于,<props> 要求键和值都必须为String 类型,而<map> 允许键和值可以是任意类型。

1. 装配Set和List

为了展示在Spring 中装配集合,让我们使用如下书店的例子。


package com.sjf.bean;

/**

 * book实体类

 * @author Administrator

 *

 */

public class Book {

	

	private String name;

	private String author;

	private double price;

	

	public void setName(String name) {

		this.name = name;

	}

 

	public void setAuthor(String author) {

		this.author = author;

	}

 

	public void setPrice(double price) {

		this.price = price;

	}

 

	@Override

	public String toString() {

		return "name:" + name + "   author:" + author + "   price:" + price;

	}

}

package com.sjf.bean;

 

import java.util.Collection;

/**

 * Bookstore实体类

 * @author Administrator

 *

 */

public class Bookstore {

	private String name;

	private Collection<Book> books;

	

	public void setName(String name) {

		this.name = name;

	}

	

	public void setBooks(Collection<Book> books) {

		this.books = books;

	}

	

	public void listAllBook(){

		System.out.println("[" + name + "]共存储一下书籍:");

		for(Book book : books){

			System.out.println(book.toString());

		}//for

	}

}

在这里最重要的是通过setBooks() 方法注入书籍(book)的集合。

让我们使用<list> 配置元素,为Bookstore赋予所拥有的书籍集合:


	<bean id = "china-pub" class = "com.sjf.bean.Bookstore">

		<property name="name" value="china-pub"/>

		<property name="books">

			<list>

				<ref bean="spring"/>

				<ref bean="spark"/>

				<ref bean="java"/>

			</list>

		</property>

	</bean>

	

	<bean id = "spring" class = "com.sjf.bean.Book">

		<property name="name" value = "Spring实战"/>

		<property name="author" value="Craig Walls"/>

		<property name="price" value="59.00"/>

	</bean>

	

	<bean id = "spark" class = "com.sjf.bean.Book">

		<property name="name" value = "Spark大数据处理技术"/>

		<property name="author" value="夏俊鸾"/>

		<property name="price" value="65.00"/>

	</bean>

	

	<bean id = "java" class = "com.sjf.bean.Book">

		<property name="name" value = "写给大忙人看的Java SE 8"/>

		<property name="author" value="Cay S. Horstmann"/>

		<property name="price" value="59.00"/>

	</bean>

<list> 元素包含一个或多个值。这里的<ref> 元素用来定义Spring 上下文中的其他Bean 引用。当然还可以使用其他的Spring 设值元素作为<list> 的成员,包括<value>、<bean> 和<null/>。实际上,<list> 可以包含另外一个<list>
作为其成员,形成多维列表。

运行结果:


[china-pub]共存储一下书籍:

name:Spring实战   author:Craig Walls   price:59.0

name:Spark大数据处理技术   author:夏俊鸾   price:65.0

name:写给大忙人看的Java SE 8   author:Cay S. Horstmann   price:59.0

如果Bean 的属性类型为数组类型或java.util.Collection 接口的任意实现(List等),都可以使用<list> 元素。换句话说,即使像下面那样配置books属性,<list> 元素也一样有效:


private List<Book> books;

或者


private Book[] books;

同样,也可以使用<set> 元素来装配集合类型或者数组类型的属性:


	<bean id = "china-pub" class = "com.sjf.bean.Bookstore">

		<property name="name" value="china-pub"/>

		<property name="books">

			<set>

				<ref bean="spring"/>

				<ref bean="spark"/>

				<ref bean="java"/>

			</set>

		</property>

	</bean>

无论<list> 还是<set> 都可以用来装配类型为java.util.Collection的任意实现或者数组的属性。不能因为属性为java.util.Set 类型,就表示用户必须使用<set> 元素来完成装配。使用<set> 元素配置java.util.List 类型的属性,虽然看起来有点怪怪的,但是这的确是可以的。如果真这样的做话,就需要确保List 中的每一个成员都必须是唯一的。

2. 装配Map


package com.sjf.bean;

 

import java.util.Map;

/**

 * Bookstore实体类

 * @author Administrator

 *

 */

public class Bookstore {

	private String name;

	private Map<String,Book> books;

	

	public void setName(String name) {

		this.name = name;

	}

	

	public void setBooks(Map<String,Book> books) {

		this.books = books;

	}

	

	public void listAllBook(){

		System.out.println("[" + name + "]共存储一下书籍:");

		for(String key : books.keySet()){

			System.out.println(key + "->" + books.get(key).toString());

		}//for

	}

}

books属性为java.util.Map 类型,Map 元素的键为String 类型,值为Book类型。因为Map 的成员是由键-值对构成的,当装配该属性时,简单的<list> 或者<set> 配置元素都无法胜任。

下面我们使用map配置books属性:


<bean id = "china-pub" class = "com.sjf.bean.Bookstore">

		<property name="name" value="china-pub"/>

		<property name="books">

			<map>

				<entry key="spring" value-ref="spring in action"/>

				<entry key="spark" value-ref="spark in action"/>

				<entry key="java" value-ref="java for busy"/>

			</map>

		</property>

	</bean>

	

	<bean id = "spring in action" class = "com.sjf.bean.Book">

		<property name="name" value = "Spring实战"/>

		<property name="author" value="Craig Walls"/>

		<property name="price" value="59.00"/>

	</bean>

	

	<bean id = "spark in action" class = "com.sjf.bean.Book">

		<property name="name" value = "Spark大数据处理技术"/>

		<property name="author" value="夏俊鸾"/>

		<property name="price" value="65.00"/>

	</bean>

	

	<bean id = "java for busy" class = "com.sjf.bean.Book">

		<property name="name" value = "写给大忙人看的Java SE 8"/>

		<property name="author" value="Cay S. Horstmann"/>

		<property name="price" value="59.00"/>

	</bean>

<map> 元素声明了一个java.util.Map 类型的值。每个<entry> 元素定义Map 的一个成员。在前边的示例中,key 属性指定了entry 的键,而value-ref属性定义了entry
的值,并引用了Spring 上下文中的其他Bean。

运行结果:


[china-pub]共存储一下书籍:

spring->name:Spring实战   author:Craig Walls   price:59.0

spark->name:Spark大数据处理技术   author:夏俊鸾   price:65.0

java->name:写给大忙人看的Java SE 8   author:Cay S. Horstmann   price:59.0

尽管在我们的示例中,使用key 属性来指定String 类型的键,使用valueref属性来指定引用类型的值,但实际上,<entry> 元素共有四个属性,分别可以用来指定entry 的键和值:

属性 用途
Key 指定map中entry的键为String。
Key-ref 指定map中entry的键为Spring上下文中其他Bean的引用。
Value 指定map中entry的值为String。
Value-ref 指定map中entry的值为Spring上下文中其他Bean的引用。

程序地址:https://github.com/sjf0115/springdemo-map

3. 装配properties集合

上面实例中books属性声明为Map 类型,我们用到了value-ref指定每一个entry 的值。这是因为每一个entry 最终都会成为Spring 上下文中的一个Bean。但是如果所配置Map 的每一个entry 的键和值都为String 类型时,我们可以考虑使用java.util.Properties
代替Map。Properties 类提供了和Map 大致相同的功能,但是它限定键和值必须为String 类型。


package com.sjf.bean;

 

import java.util.Properties;

 

/**

 * Bookstore实体类

 * @author Administrator

 *

 */

public class Bookstore {

	private String name;

	private Properties books;

	

	public void setName(String name) {

		this.name = name;

	}

	

	public void setBooks(Properties books) {

		this.books = books;

	}

	

	public void listAllBook(){

		System.out.println("[" + name + "]共存储一下书籍:");

		for(Object key : books.keySet()){

			System.out.println(key + "->" + books.get(key).toString());

		}//for

	}

}

下面我们使用property配置books属性:


<bean id = "china-pub" class = "com.sjf.bean.Bookstore">

		<property name="name" value="china-pub"/>

		<property name="books">

			<props>

				<prop key="spring in action" >Spring实战</prop>

				<prop key="spark in action" >Spark大数据处理技术</prop>

				<prop key="java for busy" >写给大忙人看的Java SE 8</prop>

			</props>

		</property>

	</bean>

<props> 元素构建了一个java.util.Properties 值, 这个Properties的每一个成员都由<prop> 元素定义。每一个<prop> 元素都有一个key 属性,其定义了Properties 每个成员的键,而每一个成员的值由<prop>
元素的内容所定义。<property> 元素用于把值或Bean 引用注入到Bean 的属性中;<props> 元素用于定义一个java.util.Properties 类型的集合值;<prop>
元素用于定义<props> 集合的一个成员。

参考:《Spring实战》

时间: 2024-10-10 18:24:06

[Spring实战系列](9)装配集合的相关文章

[Spring实战系列](11)SpEL使用表达式装配

到目前为止,我们为Bean 的属性和构造器参数装配的所有东西都是在Spring 的XML 配置文件中静态定义的. <bean id = "yoona" class = "com.sjf.bean.Student"> <property name="name" value = "yoona"/> <property name="hobby" value = "踢足球,打

[Spring实战系列](14)Bean的自动检测

即使<context:annotation-config>有助于完全消除Spring注解中的<property>和<constructor-arg>元素,但是还是不能完全消除,仍然需要使用<bean>元素显示定义Bean.因此<context:component-scan>元素出现了,它除了完成<context:annotation-config>一样的工作,还允许Spring自动检测Bean和定义Bean.这就意味着我们不使用<

[Spring实战系列](10)初探Bean生命周期

1. 生命周期流程图 Bean在Spring容器中从创建到销毁经历了若干个阶段,在每一个阶段都可以针对Spring如何管理Bean进行个性化定制. 正如你所见,在Bean 准备就绪之前,Bean 工厂执行了若干启动步骤. Spring 对Bean 进行实例化. Spring 将值和Bean 的引用注入进Bean 对应的属性中. 如果Bean 实现了BeanNameAware接口,Spring 将Bean的ID传递给setBeanName() 接口方法. 如果Bean 实现了BeanFactory

[Spring实战系列](8)Spring注入方式之setter注入

通常,JavaBean 的属性是私有的,同时拥有一组存取器方法,以setXXX() 和getXXX() 形式存在.Spring 可以借助属性的set方法来配置属性的值,以实现setter方式的注入. 1. 注入简单值 在Spring 中我们可以使用<property> 元素配置Bean 的属性.<property>在许多方面都与<constructor-arg> 类似,只不过一个是通过构造参数来注入值,另一个是通过调用属性的setter 方法来注入值. 举例说明,让我们

Spring实战3:装配bean的进阶知识

主要内容: Environments and profiles Conditional bean declaration 处理自动装配的歧义 bean的作用域 The Spring Expression Language 在装配bean—依赖注入的本质一文中,我们探讨了Spring的三种管理bean的方式:自动装配.基于JavaConfig.基于XML文件.这篇文字将探讨一些Spring中关于bean的管理的高级知识,这些技能你可能不会每天都用,但是非常重要. 3.1 Environments

[Spring实战系列](15)使用Spring基于Java的配置

并不是所有的开发人员都喜欢使用XML,所以Spring3.0 为这些人准备了一些特别的东西.可以几乎不使用XML而使用纯粹的Java代码来配置Spring应用.并且基于Java的配置拥有一些XML配置所不具有的技巧. 1. 创建基于Java的配置 即使Spring的Java配置可以让我们不使用XML就可以编写大多数的Spring配置,但是我们仍然需要极少量的XML来启用Java配置. <?xml version="1.0" encoding="UTF-8"?&

[Spring实战系列](18)注解切面

使用注解来创建切面是AspectJ 5所引入的关键特性.在AspectJ 5之前,编写AspectJ切面需要学习一种Java语言的扩展,但是AspectJ面向注解的模型可以非常简单的通过少量注解把任意类转变为切面. 回顾一下Audience类,没有任何地方让它成为一个切面,我们不得不使用XML声明通知和切点. 我们通过@AspectJ注解,我们再看看Audience类,不需要任何额外的类或Bean声明就能将它转换为一个切面. package com.sjf.bean; /** * 歌手实体类 *

[Spring实战系列](16)面向切面编程(AOP)概述

1. 简介 在软件中,有些行为对于大多数应用都是通用的.日志,安全和事务管理的确很重要,但他们是都是应用对象主动参与的行为呢?如果让应用对象只关注自己所针对的业务领域问题,而其他方面的问题由其他应用对象来处理,这样会不会更好? 在软件开发中,分布于应用中多处的功能被称为横切关注点.通常,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往直接嵌入到应用的业务逻辑中).将这些横切关注点与业务逻辑相分离是面向切面编程索要解决的. 上图展示了一个被划分为模块的典型应用.每个模块的核心功能都是为特

Spring 实战-第二章-装配Bean

Bean是Spring对象的声明(装配wiring),要使用Spring,必须先装配需要使用的对象,有3种装配的方式 自动化装配Bean 通过Java代码装配 通过XML装配 自动化装配Bean 自动化装配Bean很简单 1.声明接口 package soundsystem; public interface CompactDisc { void play(); } 2.添加注解 package soundsystem; import org.springframework.stereotype