配置简单属性值(使用 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>


<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


数组类型或 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/tree/master/springdemo-injection

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实战》