Spring不但可以将String,int等字面值注入到Bean中,还可以将集合,Map等类型的数据注入到Bean中,还可以注入配置文件中其他定义的Bean。
注入字面值:
“字面值”一般是指可用字符串表示的值,这些值可以通过<value>标签注入。默认情况下,基本类型及其封装类,String等类型都可以采用字面值注入。Spring容器在内部为字面值提供了编辑器,它可以将字符串表示的字面值转换为内部变量的相应类型。
看个例子,使用属性注入,需要提供相应的settr方法和默认的构造器:
<?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-3.0.xsd">
<bean id="car" class="com.baobaobao.Car">
<property name="brand">
<value><![CDATA[红旗&CA72]]></value>
</property>
<property name="color">
<value>red</value>
</property>
</bean>
</beans>
这儿有个特殊点:brand的属性值包含XML的特殊符号“&”XML的特殊符号一共有5个<>&"',想要在属性值里使用它要么在属性值外面加<![CDATA[属性值]]>,要么使用转义序列,不加会报错,如下:
特殊符号 | 转义序列 | 特殊符号 | 转移序列 |
< | < | " | " |
> | > | ' | ' |
& | & |
如果使用转义序列,就可以这么写:
<property name="brand">
<value>红旗&CA72</value>
</property>
引用其他Bean:
Spring容器中的Bean可以互相引用,IOC容器则充当“红娘”,看如下的例子,Boss类有一个Car类型的属性:
<?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-3.0.xsd">
<bean id="boss" class="com.baobaobao.Boss">
<property name="name">
<value>james</value>
</property>
<property name="car">
<ref bean="car"/>
</property>
</bean>
<bean id="car" class="com.baobaobao.Car">
<property name="brand">
<value>红旗&CA72</value>
</property>
<property name="color">
<value>red</value>
</property>
</bean>
</beans>
Boss的Bean通过ref建立起对car的依赖,
<ref>元素可以通过以下三个属性引用容器的bean。
bean:通过该属性可以引用同一容器或父容器的bean,最常见
local:通过该属性可以引用同一配置文件中定义的Bean,它可以利用XML解析器自动检测引用的合法性,配置时能即使发现错误。
parent:引用父容器的bean
下面来看一个子容器对父容器bean引用的例子,beans2.xml被父容器加载:
beans2.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-3.0.xsd">
<bean id="car" class="com.baobaobao.Car">
<property name="brand" value="奥迪A6"></property>
<property name="maxSpeed" value="200"></property>
<property name="price" value="300000"></property>
</bean>
</beans>
beans1.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-3.0.xsd">
<bean id="boss" class="com.baobaobao.Boss">
<property name="name">
<value>james</value>
</property>
<property name="car">
<ref parent="car"/>
</property>
</bean>
<bean id="car" class="com.baobaobao.Car">
<property name="brand">
<value>红旗&CA72</value>
</property>
<property name="maxSpeed">
<value>200</value>
</property>
<property name="price">
<value>10000</value>
</property>
</bean>
</beans>
这俩配置文件都有一个名叫car的bean。。
使用该类运行,
:
public class ParentBeanTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext pFactory = new ClassPathXmlApplicationContext(new String[]{"classpath:beans2.xml"});
//pFactory作为factory的父容器
ApplicationContext factory = new ClassPathXmlApplicationContext(new String[]{"classpath:beans1.xml"}, pFactory);
Boss boss = (Boss) factory.getBean("boss");
System.out.println(boss.getCar().getBrand());
}
}
就会打印出父容器中配置的brand的属性。
内部Bean:
如果car Bean只被boss Bean引用而不会被容器中其他Bean引用,则可以将car以内部Bean的方式注入到Boss中:
配置文件如下:
<bean id="boss" class="com.baobaobao.Boss">
<property name="car">
<bean class="com.baobaobao.Car">
<property name="brand" value="奥迪A6"/>
<property name="price" value="200000" />
</bean>
</property>
</bean>
Null值:
如果想给car的brand属性注入一个null值,如果这么配置:
<bean id="car" class="com.baobaobao.Car">
<property name="brand" value="奥迪A6">
<value></value>
</property>
</bean>
这么配置会解析为空字符串,不可行,这么做即可,如下:
<bean id="car" class="com.baobaobao.Car">
<property name="brand" >
<null />
</property>
</bean>
Spring支持级联属性的配置,假如我们想要在定义Boss时直接为Car的属性注入值,如下配置:
<bean id="boss4" class="com.baobaobao.Boss">
<property name="car.brand" value="吉利CT50"></property>
</bean>
这样,Spring将调用Boss.getCar().setBrand("吉利GT50")方法进行属性的注入操作,,必须为Boss类声明一个初始化的对象,否则,级联属性注入时会抛出异常。
例如:在Boss类中声明属性的时候初始化它,private Car car = new Car();
集合类型属性:
Spring为java常用集合类:List,Set,Map,Properties提供了专门的配置元素标签。
1)List:
给Boss类增加如下属性:
private List favorites = new ArrayList();
public List getFavorites() {
return favorites;
}
public void setFavorites(List favorites) {
this.favorites = favorites;
}
在配置文件中配置如下:
<bean id="boss4" class="com.baobaobao.Boss">
<property name="car.brand" value="吉利CT50"></property>
<property name="favorites">
<list>
<value>读书</value>
<value>看报</value>
<value>打高尔夫</value>
</list>
</property>
</bean>
这样便把List属性注入到bean里了,可以通过value注入字符串,也可以通过ref注入到其他bean中。
2)Set:
配置如下:
<property name="favorites">
<set>
<value>读书</value>
<value>看报</value>
<value>打高尔夫</value>
</set>
</property>
3)Map:
我们为Boss添加一个Map类型的jobs属性,文件配置如下:
<property name="jobs">
<map>
<entry>
<key><value>AM</value></key>
<value>会见客户</value>
</entry>
<entry>
<key><value>PM</value></key>
<value>公司内部会议</value>
</entry>
</map>
</property>
如果key和value都是对象,可以写成如下形式:
<map>
<entry>
<key><ref bean="keyBean"/></key>
<ref bean="valueBean"/>
</entry>
</map>
4)Properties
Properties可以看成是Map类型的特例,Map元素的键和值可以是任何类型的对象,而Properties的键和值只能为字符串,如下,我们为Boss类增加一个mail属性:
private Properties mails = new Properties();
public Properties getMails() {
return mails;
}
public void setMails(Properties mails) {
this.mails = mails;
}
配置文件如下配置:
<property name="mails">
<props>
<prop key="jobmail">jihaixiao@163.com</prop>
<prop key="lifeemail">xinyi_zhankuang@yahoo.com</prop>
</props>
</property>
注意:值的配置里面没有value标签。。。
5)强类型集合
JDK5.0提供的新功能。允许为集合元素指定类型,例如Boss类的jobTime,如下:
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会判断配置元素类型,自动转换。
<property name="jobTime">
<map>
<entry>
<key><value>会见客户</value></key>
<value>124</value>
</entry>
</map>
</property>
6)集合合并
Spring2.0新增集合合并的功能,允许子<bean>继承父<bean>的同名属性集合元素,并将子<bean>中配置的集合属性值和父<bean>中配置的同名属性值合并起来作为最终的Bean的属性值。配置文件如下:
<bean id="parentBoss" class="com.baobaobao.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>
在子bean的集合下增加merge属性为true表示子bean跟父bean中同名的属性值进行合并,只对子bean有效果。。。。
7)通过util命名空间配置集合类型的Bean
如果想要配置一个集合类型的Bean,而非一个集合类型的属性,那么可以通过util命名空间进行配置。
先配置头文件中如下:
<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-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
几种集合Bean的配置如下,使用id指定名字,xxx-class指定对应集合的实现类:
<util:list id="favoriteList1" list-class="java.util.LinkedList">
<value>读书</value>
<value>看报</value>
<value>高尔夫</value>
</util:list>
<util:set id="favoriteSet1">
<value>爬山</value>
<value>打球</value>
</util:set>
<util:map id="emails">
<entry key="AM" value="会见客户"></entry>
<entry key="PM" value="内部会议"></entry>
</util:map>
简化配置方式:
Spring为字面值,引用Bean和集合都提供了简化的配置方式,下面提供了简化前和简化后的版本:
1)字面值属性:
简化前 | 简化后 | |
字面值属性 | <property name="maxSpeed"> <value>200</value> </property> | <property name="maxSpeed" value="200" /> |
构造函数参数 | <constructor-arg type="java.lang.String"> <value>奥迪</value> </constructor-arg> | <constructor-arg type="java.lang.String" value="奥迪"/> |
集合元素 | <property name="jobs"> <map> <entry> <key><value>AM</value></key> <value>内部会议</value> </entry> </map> </property> | <property name="jobs"> <map> <entry key="AM" value="内部会议" /> </map> </property> |
2)引用对象属性:
简化前 | 简化后 | |
字面值属性 | <property name="car"> <ref parent="car"/> </property> | <property name="car" ref="car" /> |
构造函数参数 | <constructor-arg> <ref bean="car"/> </constructor-arg> | <constructor-arg ref="car" /> |
集合元素 | <map> <entry> <key><ref bean="keyBean"/></key> <ref bean="valueBean"/> </entry> </map> | <map> <entry key-ref="keyBean" value-ref="valueBean" /> </map> |
<ref>的简化形式对应<ref bean="XXX"> 而<ref local="XXX">和<ref parent="XXX">则没有对应的简化方式。
3)使用p命名空间
为了简化XML文件的配置,越来越多的xml采用属性而非子元素配置信息。Spring从2.5开始引入一个新的p命名空间,简化配置文件。
在头文件中加入xmlns:p="http://www.springframework.org/schema/p"
对于字面值属性,采用p:属性名=“XXX”
对于引用值属性,采用p:属性名-ref=“XXX”
正是由于p命名空间中的属性名是可变的,所以p命名空间没有对应的Schema定义文件,也无需从xsi:schemaLocation为p的命名空间指定Schema定义的文件。