您的位置:首页 > 编程语言 > Java开发

Spring容器的属性配置详解的六个专题

2016-06-28 10:35 134 查看
在spring IOC容器的配置文件applicationContext.xml里,有一些配置细节值得一提。我们将一些问题归结为以下几个专题。

专题一:字面值问题

配置的bean节点中的值,我们提出一个概念——字面值。

字面值:可用字符串表示的值.

字面值可以通过 <value> 元素标签或 value 属性进行注入。

基本数据类型及其封装类、String 等类型都可以采取字面值注入的方式

若字面值中包含特殊字符,可以使用 <![CDATA[]]> 把字面值包裹起来。

例如:(本文出自:http://my.oschina.net/happyBKs/blog/478074)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 
<bean id="car_value_id" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg name="price1">
<value>200000</value>
</constructor-arg>
<constructor-arg name="name1">
<value><![CDATA[<BM>]]></value>
</constructor-arg>
</bean>
<!-- 如果字面值包括特殊字符,可以用<![CDATA[ ]]>括起来 -->

</beans>

Car定义:

package com.happBKs.spring.iocaop.beans;

public class Car {
String name;
double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Car() {
super();
}
public Car(String name1, double price1) {
super();
this.name = name1;
this.price = price1;
}
@Override
public String toString() {
return "Car [name=" + name + ", price=" + price + "]";
}
}

测试代码:

@Test
public void test8()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
Car cBean=(Car)ctx.getBean("car_value_id");
//调用对象方法
System.out.println(cBean);
}

结果输出:

Car [name=<BM>, price=200000.0]

在上例中,属性值可以使用value子节点进行配置。

专题二:bean的属性是另一个bean

在bean类的定义中往往存在这样的情况, 另类的某个属性是另一个bean对象。这样的情况,要使得容器能够在自动生成相应对象,应该怎么做的呢。

首先我们定义一个Person类,每个Person有一个Car类型属性。

package com.happBKs.spring.iocaop.beans;

public class Person {

String username;
Car userCar;

public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Car getUserCar() {
return userCar;
}
public void setUserCar(Car userCar) {
this.userCar = userCar;
}
public Person(String username, Car userCar) {
super();
this.username = username;
this.userCar = userCar;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [username=" + username + ", userCar=" + userCar + "]";
}

}

容器配制文件:我们使用property的ref属性来引用属性类型,即建立bean之间的引用关系。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 
<bean id="car_id" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="BM"></constructor-arg>
<constructor-arg value="500000"></constructor-arg>
</bean>

<bean id="caruser" class="com.happBKs.spring.iocaop.beans.Person">
<property name="username" value="HappyBKs"></property>
<property name="userCar" ref="car_id"></property>
</bean>

</beans>

测试代码:

@Test
public void test9()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
Person pBean=(Person)ctx.getBean("caruser");
//调用对象方法
System.out.println(pBean);
}

运行结果:

Person [username=HappyBKs, userCar=Car [name=BM, price=500000.0]]

组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能. 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用

在 Bean 的配置文件中, 可以通过 <ref> 元素或 ref 属性为 Bean 的属性或构造器参数指定对 Bean 的引用.

也就是说,刚才的容器配制还可以写成:

<bean id="caruser" class="com.happBKs.spring.iocaop.beans.Person">
<property name="username" value="HappyBKs"></property>
<property name="userCar">
<ref bean="car_id"/>
</property>
</bean>

也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean。

如,上面的例子可以写成另一种内部bean的形式。这种内部bean的形式,不用再有id属性,因为它不可能被外部引用。

<bean id="caruserB" class="com.happBKs.spring.iocaop.beans.Person">
<property name="username" value="HappyBKs"></property>
<property name="userCar">
<bean class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="450000" index="1"></constructor-arg>
<constructor-arg value="Volvo" index="0"></constructor-arg>
</bean>
</property>
</bean>

测试代码:

@Test
public void test10()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
Person pBean=(Person)ctx.getBean("caruserB");
//调用对象方法
System.out.println(pBean);
}

输出结果:

Person [username=HappyBKs, userCar=Car [name=Volvo, price=450000.0]]

当 Bean 实例仅仅给一个特定的属性使用时, 可以将其声明为内部 Bean. 内部 Bean 声明直接包含在 <property> 或 <constructor-arg> 元素里, 不需要设置任何 id 或 name 属性。

内部 Bean 不能使用在任何其他地方。

专题三:特殊注入参数:null 值

我们有时需要将bean的某个属性设置为null,这在spring容器的配置文件里面怎么描述呢?

这就要用到一个特殊的标签<null/>

<bean id="caruserB" class="com.happBKs.spring.iocaop.beans.Person">
<property name="username" value="HappyBKs"></property>
<property name="userCar">
<bean class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="450000" index="1"></constructor-arg>
<constructor-arg index="0"><null/></constructor-arg>
</bean>
</property>
</bean>

运行刚才的test10方法,输出结果:

Person [username=HappyBKs, userCar=Car [name=null, price=450000.0]]

专题四:特殊注入参数:级联属性

另一种bean中比较特殊的赋值是级联属性。什么叫级联属性呢?其实你一看就明白了,就是对象的属性子对象的属性。

配置文件中配置bean的属性时,property标签不仅能直接配置该bean对应的类自身的属性,而且还可以直接配置该类的属性对象向的属性,即级联属性。

<bean id="caruserC" class="com.happBKs.spring.iocaop.beans.Person">
<property name="username" value="HappyBKs"/>
<property name="userCar" ref="car_id"/>
<property name="userCar.price" value="350000"/>
</bean>

测试代码:

@Test
public void test11()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
Person pBean=(Person)ctx.getBean("caruserC");
//调用对象方法
System.out.println(pBean);
}

输出结果:

Person [username=HappyBKs, userCar=Car [name=BM, price=350000.0]]

当然,如果配置的bean中前面用构造器注入,也可以同时使用级联属性赋值。

<bean id="caruserC" class="com.happBKs.spring.iocaop.beans.Person">
<constructor-arg value="BM"></constructor-arg>
<constructor-arg value="500000"></constructor-arg>
<property name="userCar.price" value="350000"/>
</bean>

但是有一个十分需要注意的问题:这里的级联属性被赋值的前提是级联属性所属的对象属性已经被属性注入或构造器注入赋值,否则会报异常。这一点与struts2不同,struts2这种情况会为级联属性所属对象自动生成实例,而spring不行。

专题五:集合属性

在类的属性中往往又一些属性是集合性质的类型,如List、Set、Map等,或者是一个数组类型。

在Spring中,这样的类在容器中应该如何配置呢?

在 Spring中可以通过一组内置的 xml 标签(例如: <list>, <set> 或 <map>) 来配置集合属性.

配置 java.util.List 类型的属性, 需要指定 <list> 标签, 在标签里包含一些元素. 这些标签可以通过 <value> 指定简单的常量值, 通过 <ref> 指定对其他 Bean 的引用. 通过<bean> 指定内置 Bean 定义. 通过 <null/> 指定空元素. 甚至可以内嵌其他集合。

数组的定义和 List 一样, 都使用 <list>。

配置 java.util.Set 需要使用 <set> 标签, 定义元素的方法与 List 一样。

List集合属性

那我们现在来看一个List的例子。

我们定义一个RichPerson类:它有一个userCars属性是List类型。

package com.happBKs.spring.iocaop.beans;

import java.util.List;

public class RichPerson {

String username;
List<Car> userCars;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<Car> getUserCars() {
return userCars;
}
public void setUserCars(List<Car> userCars) {
this.userCars = userCars;
}
public RichPerson(String username, List<Car> userCars) {
super();
this.username = username;
this.userCars = userCars;
}
public RichPerson() {
super();
}
@Override
public String toString() {
return "RichPerson [username=" + username + ", userCars=" + userCars
+ "]";
}
}

在applicationContext.xml中,配置如下信息:

我们将对应userCars的property标签里加入<list>标签

在<list>标签里我们逐个加入bean。

加入方法有多种,这里使用了两种:

一种是ref,引用外部的bean。如前三个单元的bean。

另一种是自己定义内部bean,与前面介绍的内部bean类似。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 
<bean id="privateCar1" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="BM"></constructor-arg>
<constructor-arg value="800000"></constructor-arg>
</bean>
<bean id="privateCar2" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="Volvo"></constructor-arg>
<constructor-arg value="500000"></constructor-arg>
</bean>

<bean id="richPerson1" class="com.happBKs.spring.iocaop.beans.RichPerson">
<property name="username" value="HappyBKs" />
<property name="userCars">
<list>
<ref bean="privateCar1" />
<ref bean="privateCar1" />
<ref bean="privateCar2" />
<bean id="privateCarSecret" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="Tank"></constructor-arg>
<constructor-arg value="100000000000"></constructor-arg>
</bean>
</list>
</property>
</bean>
</beans>

测试方法:

@Test
public void test12()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
RichPerson pBean=(RichPerson)ctx.getBean("richPerson1");
//调用对象方法
System.out.println(pBean);
}

输出结果:

RichPerson [username=HappyBKs, userCars=[Car [name=BM, price=800000.0], Car [name=BM, price=800000.0], Car [name=Volvo, price=500000.0], Car [name=Tank, price=1.0E11]]]

Map的集合属性

我们再看一个Map的集合属性的例子。

package com.happBKs.spring.iocaop.beans;

import java.util.Map;

public class RichMapPerson {

String username;
Map<String,Car> userCars;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Map<String, Car> getUserCars() {
return userCars;
}
public void setUserCars(Map<String, Car> userCars) {
this.userCars = userCars;
}
public RichMapPerson(String username, Map<String, Car> userCars) {
super();
this.username = username;
this.userCars = userCars;
}
public RichMapPerson() {
super();
}
@Override
public String toString() {
return "RichMapPerson [username=" + username + ", userCars=" + userCars
+ "]";
}

}

配置容器:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 
<bean id="privateCar1" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="BM"></constructor-arg>
<constructor-arg value="800000"></constructor-arg>
</bean>
<bean id="privateCar2" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="Volvo"></constructor-arg>
<constructor-arg value="500000"></constructor-arg>
</bean>

<bean id="richMapPerson1" class="com.happBKs.spring.iocaop.beans.RichMapPerson">
<property name="username" value="HappyBKs" />
<property name="userCars">
<map>
<entry key="WorkCar" value-ref="privateCar1"></entry>
<entry key="ShoppingCar" value-ref="privateCar2"></entry>
</map>
</property>
</bean>
</beans>

不过很可惜的是entry貌似不支持内部bean的定义,即一下情况是报错的,提示不支持此处以bean开头。

<bean id="richMapPerson1" class="com.happBKs.spring.iocaop.beans.RichMapPerson">
<property name="username" value="HappyBKs" />
<property name="userCars">
<map>
<entry key="WorkCar" value-ref="privateCar1"></entry>
<entry key="ShoppingCar" value-ref="privateCar2"></entry>
<entry key="OXOXCar">
<value type="com.happBKs.spring.iocaop.beans.Car">

<property name="name" value="taxi"></property>
<property name="price" value="50000"></property>
</value>
</entry>
</map>
</property>
</bean>

回到刚才,测试方法:

@Test
public void test13()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
RichMapPerson pBean=(RichMapPerson)ctx.getBean("richMapPerson1");
//调用对象方法
System.out.println(pBean);
}

运行结果:

RichMapPerson [username=HappyBKs, userCars={WorkCar=Car [name=BM, price=800000.0], ShoppingCar=Car [name=Volvo, price=500000.0]}]

Properties类的属性

Properties类型其实可以算Map类型的子类型:它是HashTable类型的子类噢!



现在我们来定义一个bean,用来记录数据库配置信息:

package com.happBKs.spring.iocaop.beans;

import java.util.Properties;

public class DataSourceBean {

Properties propertiesInfo;

public Properties getPropertiesInfo() {
return propertiesInfo;
}

public void setPropertiesInfo(Properties propertiesInfo) {
this.propertiesInfo = propertiesInfo;
}

public DataSourceBean(Properties propertiesInfo) {
super();
this.propertiesInfo = propertiesInfo;
}

public DataSourceBean() {
super();
}

@Override
public String toString() {
return "DataSourceBean [propertiesInfo=" + propertiesInfo + "]";
}

}

spring IOC容器配置:

<bean id="DataSourceId" class="com.happBKs.spring.iocaop.beans.DataSourceBean">
<property name="propertiesInfo">
<props>
<prop key="user">root</prop>
<prop key="password"></prop>
<prop key="jdbcUrl">jdbc:mysql:///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>

测试方法:

@Test
public void test14()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
DataSourceBean dBean=(DataSourceBean)ctx.getBean("DataSourceId");
//调用对象方法
System.out.println(dBean);
}

输出结果:

DataSourceBean [propertiesInfo={driverClass=com.mysql.jdbc.Driver, user=root, password=, jdbcUrl=jdbc:mysql:///test}]

集合类型可以外置(使用 utility scheme 定义集合)

前面提到的这些集合属性在spring ioc容器配置时,都是可以作为外部单元存在的,就像bean存在外部bean和内部bean一样。

使用基本的集合标签定义集合时, 不能将集合作为独立的 Bean 定义, 导致其他 Bean 无法引用该集合, 所以无法在不同 Bean 之间共享集合.

可以使用 util schema 里的集合标签定义独立的集合 Bean. 需要注意的是, 必须在 <beans> 根元素里添加 util schema 定义。

我们以List为例,看下面例子:

首先我们需要给applicationContext.xml加入一个命名空间:

可以用STS、eclipse的编辑工具选择下面的NameSpace编辑视图,直接勾选util命名空间。



配置文件Source如下:

<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"> 
<bean id="privateCar1" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="BM"></constructor-arg>
<constructor-arg value="800000"></constructor-arg>
</bean>
<bean id="privateCar2" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="Volvo"></constructor-arg>
<constructor-arg value="500000"></constructor-arg>
</bean>

<util:list id="carsList">
<ref bean="privateCar1" />
<ref bean="privateCar2" />
<bean class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="Audi"></constructor-arg>
<constructor-arg value="700000"></constructor-arg>
</bean>
</util:list>

<bean id="richPerson2" class="com.happBKs.spring.iocaop.beans.RichPerson">
<property name="username" value="happyBKs"/>
<property name="userCars" ref="carsList"></property>
</bean>

</beans>

除了util:list标签,spring-util-4.1命名空间中还有其他集合标签:



输出结果:

RichPerson [username=happyBKs, userCars=[Car [name=BM, price=800000.0], Car [name=Volvo, price=500000.0], Car [name=Audi, price=700000.0]]]

专题六:方便的p命名空间

为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息。

Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过 <bean> 元素属性的方式配置 Bean 的属性。

使用 p 命名空间后,基于 XML 的配置方式将进一步简化

首先,我们需要按照之前的方法导入命名空间。



之后,我们在最后加入一个bean,id为richPerson3,你发现依赖于p命名空间,现在这个bean只有一行了,十分简洁。

<?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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"> 
<bean id="privateCar1" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="BM"></constructor-arg>
<constructor-arg value="800000"></constructor-arg>
</bean>
<bean id="privateCar2" class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="Volvo"></constructor-arg>
<constructor-arg value="500000"></constructor-arg>
</bean>

<util:list id="carsList">
<ref bean="privateCar1" />
<ref bean="privateCar2" />
<bean class="com.happBKs.spring.iocaop.beans.Car">
<constructor-arg value="Audi"></constructor-arg>
<constructor-arg value="700000"></constructor-arg>
</bean>
</util:list>

<bean id="richPerson3" class="com.happBKs.spring.iocaop.beans.RichPerson" p:username="happyBKs" p:userCars-ref="carsList"/>

</beans>

测试方法:

@Test
public void test16()
{
//创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取Bean实例
RichPerson pBean=(RichPerson)ctx.getBean("richPerson3");
//调用对象方法
System.out.println(pBean);
}

运行结果:

RichPerson [username=happyBKs, userCars=[Car [name=BM, price=800000.0], Car [name=Volvo, price=500000.0], Car [name=Audi, price=700000.0]]]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: