一起学习Spring4.0(二)Bean的配置

在上一节中,我们已经学会了用Eclipse配置Spring4.0环境并创建一个简单的Spring项目。

在这一节中,将介绍Bean的配置。

本教程使用方法

从前向后阅读,本文较长,建议分9次学完,每次下载当前的代码。

配置形式

基于xml文件的方式,基于注解的方式。

Bean的配置方法

通过全类名(反射)、通过工厂方法(静态工厂方法和实例工厂方法)、FactoryBean

IOC 容器 BeanFactory 和ApplicationContext 概述

在SpringIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化。只有在容器实例化后,才可以从IOC容器里获取Bean实例并使用。

Spring 提供了两种类型的IOC容器实现。

BeanFactory

IOC容器的基本实现。BeanFactory是Spring 框架的基础设施,面向Spring本身。

ApplicationContext

提供了更多高级的特性,是BeanFactory的子接口。ApplicationContext 面向使用Spring框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的BeanFactory

无论使用何种方式,配置文件是相同的。

ApplicationContext的主要实现类:(Ctrl+T查看)
-ClassPathXmlApplicationContext:从类路径下加载配置文件
-FileSystemXmlApplicationContext:从文件系统中加载配置文件

ApplicationContext 的子接口ConfigurableApplicationContext,新增加两个主要方法:refresh()和 close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。

ApplicationContext在 初始化上下文 时就 实例化所有单例的Bean。

WebApplicationContext 是专为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。

ApplicationContext的getBean()方法

鼠标放在”ApplicationContext”上按住Ctrl 点击进入 ,
Window-> show view-> outline 查看方法,
其中没有getBean()方法,找到其父接口 ListableBeanFactory ,Ctrl+shit+T 搜索这个父接口,继续用 outline观察它的方法,其中没有getBean()方法,发现它继承了BeanFactory ,继续搜索这个父接口,观察它的方法,找到了getBean()方法。

依赖注入的方式

属性注入;构造器注入;工厂方法注入(不推荐)

属性注入

属性注入即通过setter 方法注入Bean的属性值或依赖的对象。

属性注入使用元素,使用name 属性指定Bean的属性名称,value属性或子节点指定属性值。

属性注入是实际应用中最常用的注入方式

构造方法注入

构造方法注入属性值或依赖的对象,它保证了Bean实例在实例化以后就可以使用。

构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性。

沿用上一节中的项目。
新建一个类 Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.leezp.spring.beans;
public class Car {
private String brand;
private String corp;
private double price;
private int maxSpeed;
public Car(String brand, String corp, int maxSpeed) {
super();
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
public Car(String brand, String corp, double price) {
super();
this.brand = brand;
this.corp = corp;
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price
+ ", maxSpeed=" + maxSpeed + "]";
}
}

配置 applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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 class:bean 的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 id:标识容器中的Bean,唯一 -->
<bean id="helloWorld" class="com.leezp.spring.beans.HelloWorld"><!-- 反射 -->
<property name="name" value="Spring"></property>
</bean>
<!-- 通过构造方法配置bean的属性 -->
<bean id="car" class="com.leezp.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="100000" type="double"></constructor-arg>
</bean>
<!-- 通过参数的个数和类型区分重载 ,可以在后面加个type参数区分不同构造方法 -->
<bean id="car2" class="com.leezp.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<!-- 属性值也可以使用value子节点进行配置 -->
<value>260</value>
</constructor-arg>
</bean>
</beans>

修改 Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.leezp.spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.leezp.spring.beans.Car;
public class Main {
public static void main(String[] args) {
/*
* // 创建 HelloWorld 的一个对象 HelloWorld helloWorld = new HelloWorld();
* // 为name 属性赋值 helloWorld.setName("lee");
*/
// 1. 创建Spring 的IOC 容器对象
// ApplicationContext代表IOC 容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");// 创建对象时即调用它的set方法对属性赋值
// 2. 从IOC容器中获取Bean实例
// HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
// HelloWorld helloWorld = ctx.getBean(HelloWorld.class);//这样做有缺点,配置多个
// bean的时候它不知道访问哪一个,只适用于单个bean
// 调用hello方法
// helloWorld.hello();
Car car = (Car) ctx.getBean("car");
System.out.println(car);
Car car2 = (Car) ctx.getBean("car2");
System.out.println(car2);
}
}

运行,在控制台观察结果。

1
2
3
4
HelloWorld's Constructor
setName:Spring
Car [brand=Audi, corp=ShangHai, price=100000.0, maxSpeed=0]
Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]

获取源代码

注入属性值细节

可以用字符串表示的值,可以通过元素标签value属性进行注入。
若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来。
基本数据类型及其封装类、String等类型都可以采取字面值注入的方式,可以自动类型转换。

null值和级联属性

可以使用专用的元素标签为Bean的字符串或其他对象类型的属性注入null值(意义不大,因为引用类型默认null)。

为级联属性赋值

和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。
为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。
具体见后面程序applicationContext.xml中的例子。

引用其他bean

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

在Bean的配置文件中,可以通过元素(标签节点)ref属性为Bean的属性或构造器参数指定对Bean的引用。

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

新建一个类Person.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.leezp.spring.beans;
public class Person {
private String name;
private int age;
private Car car;
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String name, int age, Car car) {
super();
this.name = name;
this.age = age;
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}

修改 Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.leezp.spring.beans;
public class Car {
private String brand;
private String corp;
private double price;
private int maxSpeed;
public Car(String brand, String corp, int maxSpeed) {
super();
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
public Car(String brand, String corp, double price) {
super();
this.brand = brand;
this.corp = corp;
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price
+ ", maxSpeed=" + maxSpeed + "]";
}
public void setPrice(double price) {
this.price = price;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
}
```

修改applicationContext.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
``` bash
<?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 class:bean 的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 id:标识容器中的Bean,唯一 -->
<bean id="helloWorld" class="com.leezp.spring.beans.HelloWorld"><!-- 反射 -->
<property name="name" value="Spring"></property>
</bean>
<!-- 通过构造方法配置bean的属性 -->
<bean id="car" class="com.leezp.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="100000" type="double"></constructor-arg>
</bean>
<!-- 通过参数的个数和类型区分重载 ,可以在后面加个type参数区分不同构造方法 -->
<bean id="car2" class="com.leezp.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<!-- 属性值也可以使用value子节点进行配置 -->
<value>260</value>
</constructor-arg>
</bean>
<bean id="person" class="com.leezp.spring.beans.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用 porperty的ref属性或ref元素建立bean之间的引用关系 -->
<!-- 指向car2 -->
<!-- <property name="car" ref="car2"></property> -->
<!-- <property name="car"> <ref bean="car2" /> </property> -->
<property name="car">
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</property>
<!-- 在struts2框架,会自动为car创建一个对象,在Spring中不可以,为级联属性赋值要先对对象Car赋值。 -->
<property name="car.maxSpeed" value="260"></property>
</bean>
<bean id="person2" class="com.leezp.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<!-- <constructor-arg ref="car"></constructor-arg> -->
<!-- 测试赋值null -->
<!-- <constructor-arg> <null /> </constructor-arg> -->
<constructor-arg ref="car"></constructor-arg>
<!-- 和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。 为级联属性赋值。 -->
<!-- 为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。 -->
<property name="car.price" value="300000"></property>
<property name="car.maxSpeed" value="260"></property>
</bean>
</beans>

修改Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.leezp.spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.leezp.spring.beans.Person;
import com.leezp.spring.beans.Car;
public class Main {
public static void main(String[] args) {
/*
* // 创建 HelloWorld 的一个对象 HelloWorld helloWorld = new HelloWorld(); //
* 为name 属性赋值 helloWorld.setName("lee");
*/
// 1. 创建Spring 的IOC 容器对象
// ApplicationContext代表IOC 容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");// 创建对象时即调用它的set方法对属性赋值
// 2. 从IOC容器中获取Bean实例
// HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
// HelloWorld helloWorld = ctx.getBean(HelloWorld.class);//这样做有缺点,配置多个
// bean的时候它不知道访问哪一个,只适用于单个bean
// 调用hello方法
// helloWorld.hello();
Car car = (Car) ctx.getBean("car");
System.out.println(car);
Car car2 = (Car) ctx.getBean("car2");
System.out.println(car2);
Person p = (Person) ctx.getBean("person");
System.out.println(p);
Person p2 = (Person) ctx.getBean("person2");
System.out.println(p2);
}
}

在控制台观察运行结果。

1
2
3
4
5
6
HelloWorld's Constructor
setName:Spring
Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260]
Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]
Person [name=Tom, age=24, car=Car [brand=Ford, corp=Changan, price=200000.0, maxSpeed=260]]
Person [name=Jerry, age=25, car=Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260]]

获取源代码

集合属性

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

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

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

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

新建一个包命名为com.leezp.spring.beans.collections。

在该包下新建一个类 Person.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.leezp.spring.beans.collections;
import java.util.List;
import com.leezp.spring.beans.Car;
public class Person {
private String name;
private int age;
private List<Car> cars;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", cars=" + cars + "]";
}
}
```

在该包下新建一个类Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
``` bash
package com.leezp.spring.beans.collections;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Person p = (Person) ctx.getBean("person3");
System.out.println(p);
}
}

修改applicationContext.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?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 class:bean 的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 id:标识容器中的Bean,唯一 -->
<bean id="helloWorld" class="com.leezp.spring.beans.HelloWorld"><!-- 反射 -->
<property name="name" value="Spring"></property>
</bean>
<!-- 通过构造方法配置bean的属性 -->
<bean id="car" class="com.leezp.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="100000" type="double"></constructor-arg>
</bean>
<!-- 通过参数的个数和类型区分重载 ,可以在后面加个type参数区分不同构造方法 -->
<bean id="car2" class="com.leezp.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<!-- 属性值也可以使用value子节点进行配置 -->
<value>260</value>
</constructor-arg>
</bean>
<bean id="person" class="com.leezp.spring.beans.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用 porperty的ref属性或ref元素建立bean之间的引用关系 -->
<!-- 指向car2 -->
<!-- <property name="car" ref="car2"></property> -->
<!-- <property name="car"> <ref bean="car2" /> </property> -->
<property name="car">
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</property>
<!-- 在struts2框架,会自动为car创建一个对象,在Spring中不可以,为级联属性赋值要先对对象Car赋值。 -->
<property name="car.maxSpeed" value="260"></property>
</bean>
<bean id="person2" class="com.leezp.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<!-- <constructor-arg ref="car"></constructor-arg> -->
<!-- 测试赋值null -->
<!-- <constructor-arg> <null /> </constructor-arg> -->
<constructor-arg ref="car"></constructor-arg>
<!-- 和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。 为级联属性赋值。 -->
<!-- 为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。 -->
<property name="car.price" value="300000"></property>
<property name="car.maxSpeed" value="260"></property>
</bean>
<!-- 测试如何配置集合属性 -->
<bean id="person3" class="com.leezp.spring.beans.collections.Person">
<property name="name" value="lee"></property>
<property name="age" value="18"></property>
<property name="cars">
<!-- 使用 list 节点为List类型的属性赋值 -->
<list>
<ref bean="car" />
<ref bean="car2" />
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</list>
</property>
</bean>
</beans>
```

在控制台观察运行结果。

1
2
3
4
5
``` bash
HelloWorld's Constructor
setName:Spring
Person [name=lee, age=18, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260], Car [brand=Ford, corp=Changan, price=200000.0, maxSpeed=0]]]
```

获取源代码


Java.util.Map通过<map>标签定义,<map>标签里可以使用多个<entry>作为子标签,每个条目包含一个键和一个值。

必须在<key>标签里定义键。

因为键和值的类型没有限制,所以可以自由地为它们指定<value>,<ref>,<bean>或<null>元素。

可以将Map的键和值作为<entry>的属性定义:简单常量使用key和value来定义;Bean引用通过key-ref和value-ref属性定义。

使用<props>定义java.util.Properties,该标签使用多个<prop>作为子标签,每个<prop>标签必须定义key属性。

在该包下新建一个类 NewPerson.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
``` bash
package com.leezp.spring.beans.collections;
import java.util.Map;
import com.leezp.spring.beans.Car;
public class NewPerson {
private String name;
private int age;
private Map<String,Car> cars;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Map<String, Car> getCars() {
return cars;
}
public void setCars(Map<String, Car> cars) {
this.cars = cars;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", cars=" + cars + "]";
}
}
```

修改applicationContext.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
``` bash
<?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 class:bean 的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 id:标识容器中的Bean,唯一 -->
<bean id="helloWorld" class="com.leezp.spring.beans.HelloWorld"><!-- 反射 -->
<property name="name" value="Spring"></property>
</bean>
<!-- 通过构造方法配置bean的属性 -->
<bean id="car" class="com.leezp.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="100000" type="double"></constructor-arg>
</bean>
<!-- 通过参数的个数和类型区分重载 ,可以在后面加个type参数区分不同构造方法 -->
<bean id="car2" class="com.leezp.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<!-- 属性值也可以使用value子节点进行配置 -->
<value>260</value>
</constructor-arg>
</bean>
<bean id="person" class="com.leezp.spring.beans.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用 porperty的ref属性或ref元素建立bean之间的引用关系 -->
<!-- 指向car2 -->
<!-- <property name="car" ref="car2"></property> -->
<!-- <property name="car"> <ref bean="car2" /> </property> -->
<property name="car">
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</property>
<!-- 在struts2框架,会自动为car创建一个对象,在Spring中不可以,为级联属性赋值要先对对象Car赋值。 -->
<property name="car.maxSpeed" value="260"></property>
</bean>
<bean id="person2" class="com.leezp.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<!-- <constructor-arg ref="car"></constructor-arg> -->
<!-- 测试赋值null -->
<!-- <constructor-arg> <null /> </constructor-arg> -->
<constructor-arg ref="car"></constructor-arg>
<!-- 和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。 为级联属性赋值。 -->
<!-- 为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。 -->
<property name="car.price" value="300000"></property>
<property name="car.maxSpeed" value="260"></property>
</bean>
<!-- 测试如何配置集合属性 -->
<bean id="person3" class="com.leezp.spring.beans.collections.Person">
<property name="name" value="lee"></property>
<property name="age" value="18"></property>
<property name="cars">
<!-- 使用 list 节点为List类型的属性赋值 -->
<list>
<ref bean="car" />
<ref bean="car2" />
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</list>
</property>
</bean>
<!-- 配置Map属性值 -->
<bean id="newPerson" class="com.leezp.spring.beans.collections.NewPerson">
<property name="name" value="Candy"></property>
<property name="age" value="20"></property>
<property name="cars">
<!-- 使用map节点及map的entry子节点配置Map类型的成员变量 -->
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
</beans>
```

修改Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
``` bash
package com.leezp.spring.beans.collections;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Person p = (Person) ctx.getBean("person3");
System.out.println(p);
NewPerson p2 = (NewPerson) ctx.getBean("newPerson");
System.out.println(p2);
}
}
```

在控制台观察运行结果。

1
2
3
4
5
``` bash
HelloWorld's Constructor
setName:Spring
Person [name=lee, age=18, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260], Car [brand=Ford, corp=Changan, price=200000.0, maxSpeed=0]]]
Person [name=Candy, age=20, cars={AA=Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], BB=Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]}]

获取源代码


配置Properties属性值。

在com.leezp.spring.beans.collections包下新建一个类 DataSource.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.leezp.spring.beans.collections;
import java.util.Properties;
public class DataSource {
private Properties properties;
@Override
public String toString() {
return "DataSource [properties=" + properties + "]";
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
```

修改applicationContext.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
``` bash
<?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.0.xsd">
<!-- 配置bean class:bean 的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 id:标识容器中的Bean,唯一 -->
<bean id="helloWorld" class="com.leezp.spring.beans.HelloWorld"><!-- 反射 -->
<property name="name" value="Spring"></property>
</bean>
<!-- 通过构造方法配置bean的属性 -->
<bean id="car" class="com.leezp.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="100000" type="double"></constructor-arg>
</bean>
<!-- 通过参数的个数和类型区分重载 ,可以在后面加个type参数区分不同构造方法 -->
<bean id="car2" class="com.leezp.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<!-- 属性值也可以使用value子节点进行配置 -->
<value>260</value>
</constructor-arg>
</bean>
<bean id="person" class="com.leezp.spring.beans.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用 porperty的ref属性或ref元素建立bean之间的引用关系 -->
<!-- 指向car2 -->
<!-- <property name="car" ref="car2"></property> -->
<!-- <property name="car"> <ref bean="car2" /> </property> -->
<property name="car">
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</property>
<!-- 在struts2框架,会自动为car创建一个对象,在Spring中不可以,为级联属性赋值要先对对象Car赋值。 -->
<property name="car.maxSpeed" value="260"></property>
</bean>
<bean id="person2" class="com.leezp.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<!-- <constructor-arg ref="car"></constructor-arg> -->
<!-- 测试赋值null -->
<!-- <constructor-arg> <null /> </constructor-arg> -->
<constructor-arg ref="car"></constructor-arg>
<!-- 和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。 为级联属性赋值。 -->
<!-- 为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。 -->
<property name="car.price" value="300000"></property>
<property name="car.maxSpeed" value="260"></property>
</bean>
<!-- 测试如何配置集合属性 -->
<bean id="person3" class="com.leezp.spring.beans.collections.Person">
<property name="name" value="lee"></property>
<property name="age" value="18"></property>
<property name="cars">
<!-- 使用 list 节点为List类型的属性赋值 -->
<list>
<ref bean="car" />
<ref bean="car2" />
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</list>
</property>
</bean>
<!-- 配置Map属性值 -->
<bean id="newPerson" class="com.leezp.spring.beans.collections.NewPerson">
<property name="name" value="Candy"></property>
<property name="age" value="20"></property>
<property name="cars">
<!-- 使用map节点及map的entry子节点配置Map类型的成员变量 -->
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
<!-- 配置Properties属性值 -->
<bean id="dataSource" class="com.leezp.spring.beans.collections.DataSource">
<property name="properties">
<!-- 使用props和prop子节点来为Properties属性赋值 -->
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="jdbcUrl">jdbc:mysql:///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
</beans>
```

修改Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
``` bash
package com.leezp.spring.beans.collections;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Person p = (Person) ctx.getBean("person3");
System.out.println(p);
NewPerson p2 = (NewPerson) ctx.getBean("newPerson");
System.out.println(p2);
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
}
}
```

在控制台观察运行结果。

1
2
3
4
5
6
``` bash
HelloWorld's Constructor
setName:Spring
Person [name=lee, age=18, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260], Car [brand=Ford, corp=Changan, price=200000.0, maxSpeed=0]]]
Person [name=Candy, age=20, cars={AA=Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], BB=Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]}]
DataSource [properties={driverClass=com.mysql.jdbc.Driver, user=root, password=root, jdbcUrl=jdbc:mysql:///test}]

使用 utility scheme定义集合

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

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

先开启Spring配置文件中的util标签:打开applicationContext.xml 配置文件。点击下面的Namespaces,在弹出的复选框中将util复选框勾选。

修改applicationContext.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?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.0.xsd">
<!-- 配置bean class:bean 的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 id:标识容器中的Bean,唯一 -->
<bean id="helloWorld" class="com.leezp.spring.beans.HelloWorld"><!-- 反射 -->
<property name="name" value="Spring"></property>
</bean>
<!-- 通过构造方法配置bean的属性 -->
<bean id="car" class="com.leezp.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="100000" type="double"></constructor-arg>
</bean>
<!-- 通过参数的个数和类型区分重载 ,可以在后面加个type参数区分不同构造方法 -->
<bean id="car2" class="com.leezp.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<!-- 属性值也可以使用value子节点进行配置 -->
<value>260</value>
</constructor-arg>
</bean>
<bean id="person" class="com.leezp.spring.beans.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用 porperty的ref属性或ref元素建立bean之间的引用关系 -->
<!-- 指向car2 -->
<!-- <property name="car" ref="car2"></property> -->
<!-- <property name="car"> <ref bean="car2" /> </property> -->
<property name="car">
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</property>
<!-- 在struts2框架,会自动为car创建一个对象,在Spring中不可以,为级联属性赋值要先对对象Car赋值。 -->
<property name="car.maxSpeed" value="260"></property>
</bean>
<bean id="person2" class="com.leezp.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<!-- <constructor-arg ref="car"></constructor-arg> -->
<!-- 测试赋值null -->
<!-- <constructor-arg> <null /> </constructor-arg> -->
<constructor-arg ref="car"></constructor-arg>
<!-- 和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。 为级联属性赋值。 -->
<!-- 为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。 -->
<property name="car.price" value="300000"></property>
<property name="car.maxSpeed" value="260"></property>
</bean>
<!-- 测试如何配置集合属性 -->
<bean id="person3" class="com.leezp.spring.beans.collections.Person">
<property name="name" value="lee"></property>
<property name="age" value="18"></property>
<property name="cars">
<!-- 使用 list 节点为List类型的属性赋值 -->
<list>
<ref bean="car" />
<ref bean="car2" />
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</list>
</property>
</bean>
<!-- 配置Map属性值 -->
<bean id="newPerson" class="com.leezp.spring.beans.collections.NewPerson">
<property name="name" value="Candy"></property>
<property name="age" value="20"></property>
<property name="cars">
<!-- 使用map节点及map的entry子节点配置Map类型的成员变量 -->
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
<!-- 配置Properties属性值 -->
<bean id="dataSource" class="com.leezp.spring.beans.collections.DataSource">
<property name="properties">
<!-- 使用props和prop子节点来为Properties属性赋值 -->
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="jdbcUrl">jdbc:mysql:///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
<!-- 配置独立的集合Bean,以供多个bean进行引用 ,需要导入util命名空间 -->
<util:list id="cars">
<ref bean="car" />
<ref bean="car2" />
</util:list>
<bean id="person4" class="com.leezp.spring.beans.collections.Person">
<property name="name" value="Jack"></property>
<property name="age" value="21"></property>
<!-- 引用配置的独立的集合Bean -->
<property name="cars" ref="cars"></property>
</bean>
</beans>

修改Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.leezp.spring.beans.collections;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Person p = (Person) ctx.getBean("person3");
System.out.println(p);
NewPerson p2 = (NewPerson) ctx.getBean("newPerson");
System.out.println(p2);
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
Person p4 = (Person) ctx.getBean("person4");
System.out.println(p4);
}
}
```

在控制台观察运行结果。

1
2
3
4
5
6
7
8
``` bash
HelloWorld's Constructor
setName:Spring
Person [name=lee, age=18, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260], Car [brand=Ford, corp=Changan, price=200000.0, maxSpeed=0]]]
Person [name=Candy, age=20, cars={AA=Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], BB=Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]}]
DataSource [properties={driverClass=com.mysql.jdbc.Driver, user=root, password=root, jdbcUrl=jdbc:mysql:///test}]
Person [name=Jack, age=21, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]]]
```

使用 p 命名空间

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

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

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

修改applicationContext.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
``` bash
<?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.0.xsd">
<!-- 配置bean class:bean 的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 id:标识容器中的Bean,唯一 -->
<bean id="helloWorld" class="com.leezp.spring.beans.HelloWorld"><!-- 反射 -->
<property name="name" value="Spring"></property>
</bean>
<!-- 通过构造方法配置bean的属性 -->
<bean id="car" class="com.leezp.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="100000" type="double"></constructor-arg>
</bean>
<!-- 通过参数的个数和类型区分重载 ,可以在后面加个type参数区分不同构造方法 -->
<bean id="car2" class="com.leezp.spring.beans.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<!-- 属性值也可以使用value子节点进行配置 -->
<value>260</value>
</constructor-arg>
</bean>
<bean id="person" class="com.leezp.spring.beans.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用 porperty的ref属性或ref元素建立bean之间的引用关系 -->
<!-- 指向car2 -->
<!-- <property name="car" ref="car2"></property> -->
<!-- <property name="car"> <ref bean="car2" /> </property> -->
<property name="car">
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</property>
<!-- 在struts2框架,会自动为car创建一个对象,在Spring中不可以,为级联属性赋值要先对对象Car赋值。 -->
<property name="car.maxSpeed" value="260"></property>
</bean>
<bean id="person2" class="com.leezp.spring.beans.Person">
<constructor-arg value="Jerry"></constructor-arg>
<constructor-arg value="25"></constructor-arg>
<!-- <constructor-arg ref="car"></constructor-arg> -->
<!-- 测试赋值null -->
<!-- <constructor-arg> <null /> </constructor-arg> -->
<constructor-arg ref="car"></constructor-arg>
<!-- 和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。 为级联属性赋值。 -->
<!-- 为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。 -->
<property name="car.price" value="300000"></property>
<property name="car.maxSpeed" value="260"></property>
</bean>
<!-- 测试如何配置集合属性 -->
<bean id="person3" class="com.leezp.spring.beans.collections.Person">
<property name="name" value="lee"></property>
<property name="age" value="18"></property>
<property name="cars">
<!-- 使用 list 节点为List类型的属性赋值 -->
<list>
<ref bean="car" />
<ref bean="car2" />
<!-- 内部bean ,不能被外部引用,只能在内部使用 -->
<bean class="com.leezp.spring.beans.Car">
<constructor-arg value="Ford"></constructor-arg>
<constructor-arg value="Changan"></constructor-arg>
<constructor-arg value="200000" type="double"></constructor-arg>
</bean>
</list>
</property>
</bean>
<!-- 配置Map属性值 -->
<bean id="newPerson" class="com.leezp.spring.beans.collections.NewPerson">
<property name="name" value="Candy"></property>
<property name="age" value="20"></property>
<property name="cars">
<!-- 使用map节点及map的entry子节点配置Map类型的成员变量 -->
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
<!-- 配置Properties属性值 -->
<bean id="dataSource" class="com.leezp.spring.beans.collections.DataSource">
<property name="properties">
<!-- 使用props和prop子节点来为Properties属性赋值 -->
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="jdbcUrl">jdbc:mysql:///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
<!-- 配置独立的集合Bean,以供多个bean进行引用 ,需要导入util命名空间 -->
<util:list id="cars">
<ref bean="car" />
<ref bean="car2" />
</util:list>
<bean id="person4" class="com.leezp.spring.beans.collections.Person">
<property name="name" value="Jack"></property>
<property name="age" value="21"></property>
<!-- 引用配置的独立的集合Bean -->
<property name="cars" ref="cars"></property>
</bean>
<!-- 通过p命名空间为bean的属性赋值,需要先导入p命名空间 ,相对于之前方式更简洁一些 -->
<bean id="person5" class="com.leezp.spring.beans.collections.Person"
p:name="Ming" p:age="22" p:cars-ref="cars">
</bean>
</beans>
```

修改Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
``` bash
package com.leezp.spring.beans.collections;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Person p = (Person) ctx.getBean("person3");
System.out.println(p);
NewPerson p2 = (NewPerson) ctx.getBean("newPerson");
System.out.println(p2);
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
Person p4 = (Person) ctx.getBean("person4");
System.out.println(p4);
Person p5 = (Person) ctx.getBean("person5");
System.out.println(p5);
}
}
```

在控制台观察运行结果。

1
2
3
4
5
6
7
8
9
``` bash
HelloWorld's Constructor
setName:Spring
Person [name=lee, age=18, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260], Car [brand=Ford, corp=Changan, price=200000.0, maxSpeed=0]]]
Person [name=Candy, age=20, cars={AA=Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], BB=Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]}]
DataSource [properties={driverClass=com.mysql.jdbc.Driver, user=root, password=root, jdbcUrl=jdbc:mysql:///test}]
Person [name=Jack, age=21, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]]]
Person [name=Ming, age=22, cars=[Car [brand=Audi, corp=ShangHai, price=300000.0, maxSpeed=260], Car [brand=Baoma, corp=<ShangHai^>, price=0.0, maxSpeed=260]]]
```

获取源代码

自动装配

XML配置里的Bean自动装配

SpringIOC容器可以自动装配Bean。需要做的仅仅是的autowire属性里指定自动装配的模式

byType(根据类型自动装配):若IOC容器中有多个与目标Bean类型一致的Bean,在这种情况下,Spring将无法判定哪个Bean最合适该属性,所以不能执行自动装配。

byName(根据名称自动装配):必须将目标Bean的名称和属性名设置的完全相同。

constructor(通过构造器自动装配):当Bean中存在多个构造器时,此种自动装配方式将会很复杂。不推荐使用

新建一个包com.leezp.spring.beans.autowire。

在该包下新建Address.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
``` bash
package com.leezp.spring.beans.autowire;
public class Address {
private String city;
private String street;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
@Override
public String toString() {
return "Address [city=" + city + ", street=" + street + "]";
}
}
```

在该包下新建Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
``` bash
package com.leezp.spring.beans.autowire;
public class Car {
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
}

在该包下新建Person.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.leezp.spring.beans.autowire;
public class Person {
private String name;
private Address address;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", address=" + address + ", car=" + car
+ "]";
}
}

在src下新建一个Spring的配置文件beans-autowire.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?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.xsd">
<bean id="address" class="com.leezp.spring.beans.autowire.Address"
p:city="NanJing" p:street="ShangHaiLu">
</bean>
<!-- <bean id="address2" class="com.leezp.spring.beans.autowire.Address"
p:city="NanJing" p:street="ShangHaiLu">
</bean> -->
<bean id="car2" class="com.leezp.spring.beans.autowire.Car"
p:brand="BMW" p:price="300000"></bean>
<!-- 手动转配 -->
<!-- <bean id="person" class="com.leezp.spring.beans.autowire.Person" p:name="Tom"
p:address-ref="address" p:car-ref="car"></bean> -->
<!-- 可以使用autowire属性指定自动装配的方式,byName根据bean的名字和当前bean的 setter风格的属性名进行自动装配,
若有匹配的,则进行自动装配;若没有匹配的,则不装配。 -->
<!-- <bean id="person" class="com.leezp.spring.beans.autowire.Person" p:name="Tom"
autowire="byName"></bean> -->
<!-- byType根据bean的类型和当前bean的属性的类型进行自动装配。若IOC容器中有一个以上的类型匹配的Bean,则抛异常。 -->
<bean id="person" class="com.leezp.spring.beans.autowire.Person"
p:name="Tom" autowire="byType"></bean>
</beans>
```

在该包下新建一个Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
``` bash
package com.leezp.spring.beans.autowire;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-autowire.xml");
Person p = (Person) ctx.getBean("person");
System.out.println(p);
}
}
```

在控制台观察运行结果。

1
2
3
``` bash
Person [name=Tom, address=Address [city=NanJing, street=ShangHaiLu], car=Car [brand=BMW, price=300000.0]]
```

获取源代码

XML配置里的Bean自动装配的缺点

在Bean配置文件里设置autowire属性进行自动装配将会装配Bean的所有属性。然而,若只希望装配个别属性时,autowire属性就不够灵活了。

autowire属性要么根据类型自动匹配,要么根据名称自动装配,不能两者兼而有之。

一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。

在整合第三方框架的时候,使用autowire的确给我们带来一些方便。

bean之间的关系

继承;依赖。

继承Bean配置

Spring允许继承Bean的配置,被继承的Bean称为父Bean,继承这个父Bean的Bean称为子Bean。

子Bean从父Bean中继承配置,包括Bean的属性配置

子Bean也可以覆盖从父Bean继承过来的配置。

新建一个包com.leezp.spring.beans.relation。

在src下新建一个Spring的配置文件beans-relation.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
``` bash
<?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.xsd">
<bean id="address" class="com.leezp.spring.beans.autowire.Address"
p:city="NanJing" p:street="ShangHaiLu"></bean>
<!-- <bean id="address2" class="com.leezp.spring.beans.autowire.Address"
p:city="NanJing" p:street="XiAnLu"></bean> -->
<!-- bean配置的继承:使用bean的parent属性指定继承哪个bean的配置 -->
<bean id="address2" p:street="XiAnLu" parent="address"></bean>
</beans>
```

在该包下新建Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
``` bash
package com.leezp.spring.beans.relation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.leezp.spring.beans.autowire.Address;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-relation.xml");
Address address = (Address) ctx.getBean("address");
System.out.println(address);
Address address2 = (Address) ctx.getBean("address2");
System.out.println(address2);
}
}
```

在控制台观察运行结果。

1
2
3
4
``` bash
Address [city=NanJing, street=ShangHaiLu]
Address [city=NanJing, street=XiAnLu]
```

父Bean可以作为配置模板,也可以作为bean实例,若只想把父bean作为模板,可以设置的abstract属性为true,这样Spring将不会实例化这个Bean(用IOC实例化它会报错)。

并不是元素里的所有属性都会被继承,比如:autowire,abstract等。

可以忽略父bean的class属性,让子bean指定自己的类,而共享相同的属性配置。但此时abstract必须设置为true(若某一个bean的class属性没有指定,则该bean必须是一个抽象bean,否则报错)。

修改beans-relation.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
``` bash
<?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.xsd">
<!-- 抽象bean:bean的abstract属性为true的bean。这样的Bean不能被IOC容器实例化,只用来被继承配置 -->
<!-- 若某一个bean的class属性没有指定,则该bean必须是一个抽象bean -->
<bean id="address" p:city="NanJing" p:street="ShangHaiLu"
abstract="true"></bean>
<!-- <bean id="address2" class="com.leezp.spring.beans.autowire.Address"
p:city="NanJing" p:street="XiAnLu"></bean> -->
<!-- bean配置的继承:使用bean的parent属性指定继承哪个bean的配置 -->
<bean id="address2" class="com.leezp.spring.beans.autowire.Address"
p:street="XiAnLu" parent="address"></bean>
<bean id="address3" class="com.leezp.spring.beans.autowire.Address"
p:street="DaLianLu" parent="address2"></bean>
</beans>
```

修改Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
``` bash
package com.leezp.spring.beans.relation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.leezp.spring.beans.autowire.Address;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-relation.xml");
// 注意抽象Bean不能被创建。否则报错:
// Error creating bean with name 'address': Bean definition is abstract
/*
* Address address = (Address) ctx.getBean("address");
* System.out.println(address);
*/
Address address2 = (Address) ctx.getBean("address2");
System.out.println(address2);
Address address3 = (Address) ctx.getBean("address3");
System.out.println(address3);
}
}
```

在控制台观察运行结果。

1
2
3
4
``` bash
Address [city=NanJing, street=XiAnLu]
Address [city=NanJing, street=DaLianLu]
```

依赖Bean配置

Spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好

如果前置依赖于多个Bean,则可以通过逗号或空格的方式配置Bean的名称

使用场景:当bean与bean直接 初始化 有先后顺序时,就需要指定他们直接的依赖关系,可以使用depends-on属性。

修改Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
``` bash
package com.leezp.spring.beans.autowire;
public class Car {
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
public Car() {
System.out.println("Car被初始化");
}
}

修改beans-relation.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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.xsd">
<!-- 抽象bean:bean的abstract属性为true的bean。这样的Bean不能被IOC容器实例化,只用来被继承配置 -->
<!-- 若某一个bean的class属性没有指定,则该bean必须是一个抽象bean -->
<bean id="address" p:city="NanJing" p:street="ShangHaiLu"
abstract="true"></bean>
<!-- <bean id="address2" class="com.leezp.spring.beans.autowire.Address"
p:city="NanJing" p:street="XiAnLu"></bean> -->
<!-- bean配置的继承:使用bean的parent属性指定继承哪个bean的配置 -->
<bean id="address2" class="com.leezp.spring.beans.autowire.Address"
p:street="XiAnLu" parent="address"></bean>
<bean id="address3" class="com.leezp.spring.beans.autowire.Address"
p:street="DaLianLu" parent="address2"></bean>
<bean id="car" class="com.leezp.spring.beans.autowire.Car"
p:brand="Audi" p:price="300000"></bean>
<!-- 要求在配置Person时,必须有一个关联的car!换句话说person这个bean依赖于Car这个bean -->
<bean id="person" class="com.leezp.spring.beans.autowire.Person"
p:name="Tom" p:address-ref="address2" depends-on="car"></bean>
</beans>
```

修改Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
``` bash
package com.leezp.spring.beans.relation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.leezp.spring.beans.autowire.Address;
import com.leezp.spring.beans.autowire.Car;
import com.leezp.spring.beans.autowire.Person;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-relation.xml");
// 注意抽象Bean不能被创建。否则报错:
// Error creating bean with name 'address': Bean definition is abstract
/*
* Address address = (Address) ctx.getBean("address");
* System.out.println(address);
*/
Address address2 = (Address) ctx.getBean("address2");
System.out.println(address2);
Address address3 = (Address) ctx.getBean("address3");
System.out.println(address3);
Person person = (Person) ctx.getBean("person");
System.out.println(person);
}
}
```

在控制台观察运行结果。

1
2
3
4
5
``` bash
Car被初始化
Address [city=NanJing, street=XiAnLu]
Address [city=NanJing, street=DaLianLu]
Person [name=Tom, address=Address [city=NanJing, street=XiAnLu], car=null]

获取源代码

bean的作用域

singleton ; prototype ; WEB 环境作用域

singleton:默认值。容器初始化时创建bean实例,在整个容器的生命周期内只创建这一个bean。单例的。

创建Spring配置文件beans-scope.xml。

1
2
3
4
5
6
7
8
9
10
11
12
<?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的scope属性来配置bean的作用域 。 singleton:默认值。**容器初始化时**创建bean实例,在整个容器的生命周期内只创建这一个bean。单例的。 -->
<bean id="car" class="com.leezp.spring.beans.autowire.Car" scope="prototype">
<property name="brand" value="Audi"></property>
<property name="price" value="200000"></property>
</bean>
</beans>
```

修改包com.leezp.spring.beans.autowire下的Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
``` bash
package com.leezp.spring.beans.autowire;
public class Car {
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
public Car() {
System.out.println("Car被初始化");
}
}
```

创建包com.leezp.spring.beans.scope。

在包下创建Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
``` bash
package com.leezp.spring.beans.scope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.leezp.spring.beans.autowire.Car;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-scope.xml");
Car car = (Car) ctx.getBean("car");
Car car2 = (Car) ctx.getBean("car");
System.out.println(car == car2);
}
}
```

在控制台观察运行结果。

1
2
3
4
5
``` bash
Car被初始化
Car被初始化
false
```

使用外部属性文件

在配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等),而这些部署细节实际上需要和Bean配置相分离。

Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中。可以在Bean配置文件里使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件里加载属性,并使用这些属性来替换变量。

Spring还允许在属性文件中使用${propName},以实现属性之间的相互引用。

注册PropertyPlaceholderConfigurer。

Spring2.0:

1
2
3
4
``` bash
<!-- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties"></property> </bean> -->
```

Spring2.5:

1
2
3
``` bash
<context:property-placeholder location="classpath:db.properties" />
```

新建beans-properties.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
``` bash
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property> <property name="password"
value="root"></property> <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
</bean> -->
<!-- Spring2.0 -->
<!-- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties"></property> </bean> -->
<!-- Spring2.5以后:可通过<context:property-placeholder元素简化,导入属性文件 -->
<!-- <bean>中添加context Schema定义 -->
<context:property-placeholder location="classpath:db.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 使用外部属性文件的属性 -->
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
</bean>
</beans>
```

新建db.properties属性文件。

1
2
3
4
5
6
``` bash
user=root
password=root
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/test
```

新建包com.leezp.spring.beans.properties。在该包下新建Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
``` bash
package com.leezp.spring.beans.properties;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) throws SQLException {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-properties.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource.getConnection());
}
}
```

在控制台观察运行结果。

1
2
3
``` bash
com.mchange.v2.c3p0.impl.NewProxyConnection@170ed6ab
```

获取源代码

spEL

Spring表达式或语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言

语法类似于EL:SpEL使用#{…}作为界定符,所有在大括号中的字符都将被认为是SpEL

SpEL为bean的属性进行动态赋值提供了便利

通过SpEL可以实现:
1.通过bean的id对bean进行引用。
2.调用方法以及引用对象中的属性。
3.计算表达式的值。
4.正则表达式的匹配。

SpEL:字面量

字面量的表示:
1.整数:<property name=”count” value=”#{5}”/>
2.小数:<property name=”frequency” value=”#{20.1}”/>
3.科学计数法:<property name=”capacity” value=”#{1e3}”/>
4.String可以使用单引号或者双引号作为字符串的界定符号:
<property name=”name” value=”#{‘lee’}“/> 或 <property name=”name” value=’#{“lee”}‘/>
5.Boolean:<property name=”enabled” value=”#{false}”/>

仅仅赋字面值用SpEL的意义不大。重要作用是后面的操作。

SpEL:引用Bean、属性和方法

引用其他对象

1.<!–通过value属性和SpEL配置Bean之间的应用关系–>
<property name=”prefix” value=”#{prefixGenerator}”></property>

2.引用其他对象的属性
<!–通过value属性和SpEL配置 suffix属性值为另一个Bean的suffix–>
<property name=”suffix” value=”#{sequenceGenerator2.suffix}”/>

3.调用其他方法,还可以链式操作

<!–通过value属性和SpEL配置 suffix属性值为另一个Bean的方法的返回值–>
<property name=”suffix” value=”#{sequenceGenerator2.toString()}”/>

<!–方法的连缀–>
<property name=”suffix” value=”{sequenceGenerator2.toString().toUpperCase()}”/>

4.调用静态方法或静态属性

通过T()调用一个类的静态方法,它将返回一个Class Object,然后再调用相应的方法或属性:
<property name=”initValue” value=”#{T(java.lang.Math).PI}”/>

新建一个包com.leezp.spring.beans.spel。

在该包下新建Address.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
``` bash
package com.leezp.spring.beans.spel;
public class Address {
private String city;
private String street;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
@Override
public String toString() {
return "Address [city=" + city + ", street=" + street + "]";
}
}
```

在该包下新建Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
``` bash
package com.leezp.spring.beans.spel;
public class Car {
private String brand;
private double price;
// 轮胎周长
private double tyrePerimeter;
public double getTyrePerimeter() {
return tyrePerimeter;
}
public void setTyrePerimeter(double tyrePerimeter) {
this.tyrePerimeter = tyrePerimeter;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + ", typePerimeter="
+ tyrePerimeter + "]";
}
public Car() {
// System.out.println("Car被初始化");
}
}

在该包下新建Person.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.leezp.spring.beans.spel;
public class Person {
private String name;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
//引用 address bean的city属性
private String city;
//根据car的price确定info:car的price>=300000:金领;否则:白领
private String info;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", city=" + city + ", info=" + info
+ ", car=" + car + "]";
}
}

新建beans-spel.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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="address" class="com.leezp.spring.beans.spel.Address">
<!-- 使用SpEL为属性赋一个字面值 -->
<property name="city" value="#{'ChengDu'}"></property>
<property name="street" value="#{'YuLinLu'}"></property>
</bean>
<bean id="car" class="com.leezp.spring.beans.spel.Car">
<property name="brand" value="Audi"></property>
<property name="price" value="400000"></property>
<!-- 使用SpEL引用类的静态属性 -->
<property name="tyrePerimeter" value="#{T(java.lang.Math).PI*2*30}"></property>
</bean>
<bean id="person" class="com.leezp.spring.beans.spel.Person">
<!-- 使用SpEL来引用其他的Bean -->
<property name="car" value="#{car}"></property>
<!-- 使用SpEL来引用其他的Bean属性 -->
<property name="city" value="#{address.city}"></property>
<property name="info" value="#{address.street}"></property>
</bean>
</beans>
```

新建Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
``` bash
package com.leezp.spring.beans.spel;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-spel.xml");
Address a = (Address) ctx.getBean("address");
System.out.println(a);
Car car = (Car) ctx.getBean("car");
System.out.println(car);
Person p = (Person) ctx.getBean("person");
System.out.println(p);
}
}
```

在控制台观察运行结果。

1
2
3
4
5
``` bash
Address [city=ChengDu, street=YuLinLu]
Car [brand=Audi, price=400000.0, typePerimeter=188.49555921538757]
Person [name=null, city=ChengDu, info=YuLinLu, car=Car [brand=Audi, price=400000.0, typePerimeter=188.49555921538757]]
```

获取源代码

SpEL支持的运算符号

1.算数运算符:+,-,*,/,%,^

1
2
3
4
5
6
7
8
``` bash
<property name="addition" value="#{counter.total+1}"></property>
<property name="subtraction" value="#{counter.total-1}"></property>
<property name="perimeter" value="#{2*T(java.lang.Math).PI*circle.radius}"></property>
<property name="average" value="#{counter.total/counter.count}"></property>
<property name="remainder" value="#{counter.total%counter.count}"></property>
<property name="area" value="#{T(java.lang.Math).PI*circle.radius^2}"></property>
```

2.加号还可以用作字符串连接:
<constructor-arg value=”#{performer.firstName+’’+performer.lastName}”/>

3.比较运算符:<,>,==,<=,>=,lt,gt,eq,le,ge
<property name=”equal” value=”#{counter.total==100}”/>
<property name=”hasCapacity” value=”#{counter.total le 10000}”/>

4.逻辑运算符号 and,or,not,!
<property name=”largeCircle” value=”#{shape.kind==’circle’ and shape.perimeter gr<10000}”/>
<property name=”ww” value=”#{!product.available}”/>
<property name=”zz” value=”#{not product.available}”/>

5.if-else运算符(三目运算符) ?:

6.if-else的变体
<constructor-arg value=”#{lee.song} ?: ‘ChunHua’}”/>

7.正则表达式:matches
<constructor-arg value=”#{admin.email matches ‘[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}’}”/>

IOC容器中Bean的生命周期

SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务。

SpringIOC容器对Bean的生命周期进行管理的过程:
1.通过构造器或工厂方法创建Bean实例
2.为Bean的属性设置值和对其他Bean的引用
3.调用Bean的初始化方法
4.Bean可以使用了
5.当容器关闭时,调用Bean的销毁方法

在Bean的声明里设置init-method和destroy-method属性,为Bean指定初始化和销毁方法。

在src下创建包com.leezp.spring.beans.cycle。

在该包下创建Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
``` bash
package com.leezp.spring.beans.cycle;
public class Car {
public Car() {
System.out.println("Car's Constructor...");
}
private String brand;
public void setBrand(String brand) {
System.out.println("setBrand...");
this.brand = brand;
}
public void init() {
System.out.println("init...");
}
public void destroy() {
System.out.println("destroy...");
}
}
```

创建beans-cycle.xml配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
``` bash
<?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" class="com.leezp.spring.beans.cycle.Car"
init-method="init" destroy-method="destroy">
<property name="brand" value="Audi"></property>
</bean>
</beans>
```

创建Main.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
``` bash
package com.leezp.spring.beans.cycle;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans-cycle.xml");
Car car = (Car) ctx.getBean("car");
System.out.println(car);
ctx.destroy();
}
}
```

在控制台观察运行结果。

1
2
3
4
5
6
7
``` bash
Car's Constructor...
setBrand...
init...
com.leezp.spring.beans.cycle.Car@22967f8e
destroy...
```

创建Bean后置处理器

Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理

Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非单一实例,其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性。

对Bean后置处理器而言,需要实现Interface BeanPostProcessor接口。在初始化方法被调用前后,Spring将把每个Bean实例分别传递给上述接口的以下两个方法:postProcessBeforeInitialization和postProcessAfterInitialization。

添加Bean后置处理器后Bean的生命周期

SpringIOC容器对Bean的生命周期进行管理的过程:
1.通过构造器或工厂方法创建Bean实例
2.为Bean的属性设置值和对其他Bean的引用
3.将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法
4.调用Bean的初始化方法
5.将Bean实例传递给Bean后置处理器的PostProcessAfterInitialization方法
6.Bean可以使用了
7.当容器关闭时,调用Bean的销毁方法

修改Car.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
``` bash
package com.leezp.spring.beans.cycle;
public class Car {
public Car() {
System.out.println("Car's Constructor...");
}
private String brand;
public void setBrand(String brand) {
System.out.println("setBrand...");
this.brand = brand;
}
public void init() {
System.out.println("init...");
}
public void destroy() {
System.out.println("destroy...");
}
@Override
public String toString() {
return "Car [brand=" + brand + "]";
}
}

新建MyBeanPostProcessor.java。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.leezp.spring.beans.cycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization" + bean + ","
+ beanName);
if ("car".equals(beanName)) {
//可以在这里过滤bean
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
System.out
.println("postProcessAfterInitialization" + arg0 + "," + arg1);
// 在这里可以对Bean进行额外的配置
Car car = new Car();
car.setBrand("Ford");
return car;
}
}

修改beans-cycle.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="car" class="com.leezp.spring.beans.cycle.Car"
        init-method="init" destroy-method="destroy">
        <property name="brand" value="Audi"></property>
    </bean>

    <!-- 实现BeanPostProcessor接口,并具体提供两个方法的实现 -->
    <!-- 配置Bean的后置处理器 -->
    <bean class="com.leezp.spring.beans.cycle.MyBeanPostProcessor"></bean>

</beans>

在控制台观察运行结果。

Car's Constructor...
setBrand...
postProcessBeforeInitializationCar [brand=Audi],car
init...
postProcessAfterInitializationCar [brand=Audi],car
Car's Constructor...
setBrand...
Car [brand=Ford]
destroy...

版权声明:本文为博主原创文章,转载请注明出处 Leezp’s Blog

点击按钮打赏作者!