在Spring配置文件中,用户不但可以将String、int等字面值注入到Bean中,还可以将集合、Map等类型的数据注入到Bean中,此外还可以注入配置文件中其他定义的Bean。
1.字面值
所谓“字面值”一般是指可用字符串表示的值,这些值可以通过< value >元素标签进行注入。在默认情况下,基本数据类型及其封装类、String等类型都可以采取字面注入的方式。
在下面的示例中,我们为Car注入了两个属性值并在Spring配置文件中使用字面值提供配置值:
<bean id="car" class="com.baobaotao.attr.Car">
<property name="maxSpeed"><value>200</value></property>
<property name="brand"><value><![CDATA[红旗&CA72]]></value></property>
</bean>
由于brand属性值value:红旗&CA72里面包含了一个XML特殊符号,因此我们特意在属性值外添加了一个 <![CDATA[]]> 的XML特殊处理标签,<![CDATA[]]>的作用是让XML解析器将标签中的字符串当作普通的文本对待,以防止某些字符串对XML格式造成破坏。
XML中共有5个特殊的字符,分别是 & < > " ’ 。如果配置文件中的注入值包括这些特殊字符,就需要特殊的处理。处理方式包括1.使用上面使用过的< ![CDATA[]] >这一特殊处理标签。2.使用XML转义序列表示这些特殊的字符,这5个特殊字符所对应的XML转移序列见下表:
特殊符号 | 转义序列 |
---|---|
< | < ; |
< | > ; |
& | & |
" | " ; |
’ | &apos ; |
如果使用XML转义序列,我们可以使用以下的配置进行替换:
<property name="brand"><value>红旗&CA72</value></property>
同时,我们还需要注意:一般情况下,XML解析器会忽略元素标签内部字符串的前后空格,但Spring却不忽略元素标签内部字符串的前后空格,如我们通过以下的配置为brand属性提供注入值:
<property name="brand"><value>空格红旗CT72空格</value></property>
Spring会将”红旗CT72“连同前后空格一起赋给brand属性。
2.引用其他Bean
Spring IoC容器中定义的Bean可以相互引用,IoC容器充当着红娘的作用。下面我们创建一个新的Boss类,Boss类中拥有一个Car类型的属性:
package com.baobaotao.attr;
public class Boss {
private Car car;
public void setCar(Car car){
this.car=car;
}
}
boss的Bean通过< ref >元素引用car Bean,建立其boss对car的依赖:
<?xml version="1.0" encoding="UTF-8"?>
<bean id="car" class="com.baobaotao.attr.Car"/>
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="car"> <ref bean="car"></ref></property>
</bean>
< ref >元素可以通过以下三个属性引用容器中的其他Bean。
1.bean:通过该属性可以引用同一容器或父容器的Bean,这是最常见的形式。
2.local:通过概述性只能引用同一配置文件中定义的Bean,它可以利用XML解析器自动检查引用的合法性,以便在开发编写配置时能够即使发现并纠正配置的错误。
3.parent:引用父容器中的Bean,如< ref parent=“car”>的配置说明car的Bean是父容器中的Bean。
为了说明子容器对父容器中的Bean的引用,我们来看一个具体的例子。
假设有两个配置文件:beans1.xml以及beans2.xml,其中beans1.xml被父容器加载,其配置内容如下:
<bean id="car" class="com.baobaotao.attr.Car">
<property name="brand" value="红旗CA72"/>
<property name="maxSpeed" value="200"/>
<property name="price" value="2000.00"/>
</bean>
而beans2.xml被子容器加载,其配置如下内容所示:
<bean id="car" class="com.baobaotao.attr.Car">
<property name="brand" value="吉利CT5"/>
<property name="maxSpeed" value="100"/>
<property name="price" value="1000.00"/>
</bean>
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="car" ><ref parent="car"/></property>
</bean>
在beans1.xml中配置了一个car Bean,在beans2.xml中也配置了一个car Bean。分别通过父子容器加载beans1.xml和beans2.xml,beans2.xml中的boss通过< ref parent=“car” >将引用到父容器中的car。
3.内部Bean
如果car Bean只被boss Bean引用而不会被容器中其他的Bean引用,则可以将car以内部Bean的方式放入到Bean中。
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="car">
<bean id="car" class="com.baobaotao.attr.Car">
<property name="maxSpeed" value="200"/>
<property name="price" value="2000.00"/>
</bean>
</property>
</bean>
内部Bean和Java代码中匿名内部类很相似,即没有名字,也不能被其他Bean引用,只能在声明处为外部Bean提供实例注入。
4.null值
如果用户尝试通过以下的配置方式为car的brand属性注入一个null值,将会得到一个令人失望的结果:
<bean id="car" class="com.baobaotao.attr.Car">
<property name="brand"><value></value></property>
</bean>
Spring会将< value >以及< /value >解析为一个空字符串,那如何为属性设置一个null的注入值呢?
答案是必须使用专用的< null/ >元素标签,通过它可以为Bean的字符串或其他对象类型注入null值:
<property name="brand"><null/></property>
上面的配置等同于调用car.setBrand(null)的方法。
5.级联属性
Spring支持级联属性的配置。
假设我们希望在定义Boss时直接为Car的属性提供注入值,则可以采取以下的配置方式:
<bean id="boss3" class="com.baobaotao.attr.Boss">
<property name="car.brand" value="吉利CT50"/>
</bean>
Spring没有对级联属性的层级数进行限制,只要配置的Bean拥有对应于级联属性的类结构,就可以配置任意层及的级联属性,如< property name=“car.wheel.brand” value=“双星”/>定义了具有三层结构的级联属性。
6.集合类型属性
java.util包中的集合类时最常用的数据结构类型,主要包括List、Set、Map、Properties,Spring为这些集合类型属性提供了专门的配置元素标签。
List
我们为Boss添加一个List类型的favorites属性:
package com.baobaotao.attr;
public class Boss{
private List favorites=new ArrayList();
public List getFavorites(){
return favorites;
}
public void setFavorites(List favorites){
this.favorites=favorites;
}
}
对用Spring中的配置片段如下所示:
<bean id="boss1" class="com.baobaotao.attr.Boss">
<property name="favorites">
<list>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</list>
</property>
</bean>
List属性既可以通过< value >注入字符串,也可以通过< ref >注入容器中其他的Bean。
Set
如果Boss的favorites属性是java.util.Set,则采用如下的配置方式:
<bean id="boss1" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
</bean>
Map
下面,我们为Boss添加一个Map类型的jobs属性:
public class Boss{
private Map jobs=new HashMap();
public Map getJobs(){
return jobs;
}
public void setMap(Map jobs){
this.jobs=jobs;
}
}
在配置文件中,可以通过以下方式为jobs属性提供配置值:
<bean id="boss1" class="com.baobaotao.attr.Boss">
<property name="jobs">
<map>
<entry>
<key><value>AM</value></key>
<value>会见客户</value>
<key><value>PM</key></value>
<value>公司内部会议</value>
</entry>
</map>
</property>
</bean>
假如某一Map元素的键和值都是对象,则可以采用以下的配置方式:
<entry>
<key><ref bean="keyBean"/></key>
<ref bean="valueBean"/>
</entry>
Properties
Properties类型其实可以看成是Map类型的特例。Map元素的键和值可以为任何类型的对象,而Properties属性的键和值都只能是字符串,我们为Boss添加一个Properties类型的mail值:
public class Boss{
private Properties mails=new Properties();
public Properties getMails(){
return mails;
}
public void setProperties(Properties mails){
this.mails=mails;
}
}
下面的配置片段为mails提供了配置:
<bean id="boss1" class="com.baobaotao.attr.Boss">
<property name="mails">
<props>
<prop key="jobMail">john-office@baobaotao.com</prop>
<prop key="lifeMail">john-life@baobaotao.com</prop>
</prop>
</property>
</bean>
因为Properties键值对只能是字符串,因此其配置比Map的配置要简单一些,注意值的配置没有< value >子元素标签。
强类型集合
下面的Boss类中的jobTime属性就采用了强类型的Map类型:元素的键为String类型:而值为Integer类型。
public class Boss{
private Map<String,Integer>jobTime=new HashMap<String,Integer>();
public Map<String,Integer>getJobTime(){
return jobTime;
}
public void setJobTime(Map<String,Integer>JobTime){
this.jobTime=jobTime;
}
}
在Spring中的配置和非强类型集合相同:
<bean id="boss1" class="com.baobaotao.attr.Boss">
<property name="jobTime">
<map>
<entry>
<key><value>会见客户</value></key>
<value>124</value>
</entry>
</map>
</property>
</bean>
但是Spring容器在注入强类型集合时,会判断元素的类型,将设置值转换为对应的数据类型。
集合合并
Spring2.0新增了集合合并的功能,允许子< bean >继承父< bean >的同名属性集合元素,并将子< bean >中配置的集合属性值和父< bean >中配置的同名属性值合并起来作为Bean的属性值。
<bean id="parentBoss" abstract="true" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
</bean>
<bean id="childBoss" parent="parentBoss">
<property name="favorites">
<set merge="true">
<value>爬山</value>
<value>高尔夫</value>
</set>
</property>
</bean>
在代码中通过merge="true"属性只是子< bean >和父< bean >中同名的属性值进行合并,即子Bean的favorites集合将最终拥有5个元素。如果设置为merge=“false”,则不会和父< bean >同名集合属性进行合并,即子Bean的favorites属性只有两个元素。
7.简化配置方式
前面我们都采用了完整配置格式的配置方式,但是Spring为字面值、引用Bean以及集合都提供了简化的配置方式。如果没有用到完整配置格式的特殊功能,用户可以使用简化的配置方式。下面我们分别为上面的配置方式提供简化版的配置写法:
字面值属性值
关于字面值属性:
<property name="maxSpeed"><value>200</value></property>//简化前
<property name="maxSpeed" value="200"/>
关于构造函数参数:
<constructor-arg type="java.lang.String"><value>红旗CA72</value></constructor-arg>//简化前
<constructor-arg type="java.lang.String" value="红旗CA72"/>//简化后
关于集合元素:
<map>
<entry>
<key><value>AM</value></key>
<value>会见客户</value>
</entry>
</map>//简化前
<map>
<entry key="AM" value="会见客户"/>
</map>//简化后
引用对象属性
关于字面值属性:
<property name="car"><ref bean="car"></ref></property>//简化前
<property name="car" ref bean="car"/>
关于构造函数参数:
<constructor-arg><ref bean="car"></ref></constructor-arg>//简化前
<constructor-arg ref bean="car"/>//简化后
关于集合元素:
<map>
<entry>
<key><ref bean="keyBean"></ref></key>
<ref bean="valueBean"></ref>
</entry>
</map>//简化前
<map>
<entry key-ref="keyBean" value-ref="valueBean"/>
</map>//简化后
需要注意< ref >的简化形式对应于< ref bean=“XXX” >,而< ref local=“XXX” >以及< ref parent=“XXX” >没有对应的简化形式。
使用p命名空间
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息,Spring2.5开始引入了一个新的p命名空间,可以通过< bean >元素属性的方式配置Bean的属性。
使用p命名空间之前:
<bean id="car" class="com.baobaotao.ditype.Car">
<property name="brand" value="红旗CA72"/>
<property name="maxSpeed" value="200"/>
<property name="price" value="20000.00"/>
</bean>
<bean id="boss" class="com.baobaotao.ditype.Boss">
<property name="car" ref="car"/>
</bean>
使用p命名空间后:
<bean id="car" class="com.baobaotao.ditype.Car" p:brand="红旗CA72" p:maxSpeed="200" p:price="20000.00"/>
<bean id="boss" class="com.baobaotao.ditype.Boss" p:car-ref="car"/>