自动装配
1. XML配置中的Bean自动装配
Spring IOC容器可以自动装配Bean.需要做的仅仅是在<bean>
的autowire属性中指定自动装配的模式
自动装配模式:
byType(根据类型自动装配):若IOC中有多个与目标Bean类型一致的Bean.在这种情况下Spring无法判断那个Bean最适合该属性,因此无法执行自动装配
byName(根据名称自动装配):必须将目标Bean的名称和属性名设置的完全相同
constructor(通过构造器自动装配):当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 autowire;
public class person { private String name; private Address address; private Car car;
@Override public String toString() { return "person{" + "name='" + name + '\'' + ", address=" + address + ", car=" + car + '}'; }
public void setName(String name) { this.name = name; }
public void setAddress(Address address) { this.address = address; }
public void setCar(Car car) { this.car = car; } }
|
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 31 32 33
| package autowire;
class Address { private String city; private String street;
@Override public String toString() { return "Address{" + "city='" + city + '\'' + ", street='" + street + '\'' + '}'; }
public void setCity(String city) { this.city = city; }
public void setStreet(String street) { this.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
| package autowire;
public class Car { private String brand; private double price;
@Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; }
public void setBrand(String brand) { this.brand = brand; }
public void setPrice(double price) { this.price = price; } }
|
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
| package autowire;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("autowire/autowire.xml"); person person = (person) applicationContext.getBean("person"); System.out.println(person.toString()); } }
|
autowire.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?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="autowire.Address" p:city="HeFei" p:street="ShuangDun"/> <bean id="car" class="autowire.Car" p:brand="Audi" p:price="10000"/>
<bean id="person" class="autowire.person" p:name="Tom" autowire="byType"/>
</beans>
|
三种方式输出结果都是
1
| person{name='Tom', address=Address{city='HeFei', street='ShuangDun'}, car=Car{brand='Audi', price=10000.0}}
|
2. 自动装配的缺点
- 在Bean配置文件中设置autowire属性进行自动装配将会匹配Bean的所有属性.然而若只希望装配个别属性时,autowire就不够灵活了
- autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之
- 一般情况下,在实际项目中很少使用自动装配功能.因为和自动装配带来的好处比起来,明确清晰的配置文档更有说服力一点
Bean之间的关系
继承&依赖
1. 继承
先看一个例子:
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 31 32 33
| package relation;
public class Address { private String city; private String street;
@Override public String toString() { return "Address{" + "city='" + city + '\'' + ", street='" + street + '\'' + '}'; }
public void setCity(String city) { this.city = city; }
public void setStreet(String street) { this.street = street; } }
|
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 relation;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Address address = (Address) applicationContext.getBean("address"); System.out.println(address); Address address_1 = (Address) applicationContext.getBean("address_1"); System.out.println(address_1); } }
|
applicationContext.xml
1 2 3 4 5 6 7
| <?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="relation.Address" p:city="Beijing" p:street="NanJingLu"/> <bean id="address_1" class="relation.Address" p:city="HeFei" p:street="NanJingLu"/> </beans>
|
运行结果为
1 2
| Address{city='Beijing', street='NanJingLu'} Address{city='HeFei', street='NanJingLu'}
|
可以发现其中配置的两个bean基本相同,因此第二个bean可以继承第一个bean,将applicationContext.xml修改为以下内容:
1 2 3 4 5 6 7
| <?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="relation.Address" p:city="Beijing" p:street="NanJingLu"/> <bean id="address_1" parent="address" p:city="HeFei"/> </beans>
|
结果相同
- Spring允许继承Bean的配置,被继承的Bean成为父Bean.继承这个Bean的Bean成为子Bean
- 子Bean从父Bean中继承配置,包括Bean的属性配置
- 子Bean可以覆盖父Bean继承来的配置
- 父Bean可以作为配置模板,也可以作为Bean实例.若只想把父Bean作为模板,可以设置
<bean>
的abstract属性为true,这样Sprint将不会实例化这个Bean
- 并不是
<bean>
中所有属性都会被继承,比如:autowire,abstract等
- 也可以忽略父Bean的class属性,让子Bean制定自己的类,而共享相同的属性配置.但此时abstract必须设置为true
2. 依赖
Spring允许用户通过depend-on属性设定Bean前置依赖的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
| package relation;
public class Person { private String name; private Address address; private Car car;
@Override public String toString() { return "person{" + "name='" + name + '\'' + ", address=" + address + ", car=" + car + '}'; }
public void setCar(Car car) { this.car = car; }
public void setName(String name) { this.name = name; }
public void setAddress(Address address) { this.address = address; } }
|
Address.java同上
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
| package relation;
public class Car { private String brand; private int speed; private double price;
@Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", speed=" + speed + ", price=" + price + '}'; }
public void setBrand(String brand) { this.brand = brand; }
public void setSpeed(int speed) { this.speed = speed; }
public void setPrice(double price) { this.price = price; } }
|
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
| package relation;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Person person = (Person) applicationContext.getBean("person"); System.out.println(person); } }
|
applicationContext.xml
1 2 3 4 5 6 7 8
| <?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="relation.Address" p:city="Beijing" p:street="NanJingLu"/> <bean id="address_1" parent="address" p:city="HeFei"/> <bean id="person" class="relation.person" p:name="Tom" p:address-ref="address"/> </beans>
|
输出:
1
| person{name='Tom', address=Address{city='Beijing', street='NanJingLu'}, car=null}
|
如果要求person这个Bean一定要绑定一个Car,即person依赖于Car:
1 2 3 4 5 6 7 8 9
| <?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="relation.Address" p:city="Beijing" p:street="NanJingLu"/> <bean id="address_1" parent="address" p:city="HeFei"/> <bean id="car" class="relation.Car" p:brand="Audi" p:price="100000" p:speed="200"/> <bean id="person" class="relation.Person" p:name="Tom" p:address-ref="address" depends-on="car"/> </beans>
|
运行结果和之前仍然相同,但是已经这个id为car的Bean已经在person实例化之前被实例化了,只是car不属于person,所以person的car仍然为null
Bean的作用域
通过在<bean>
标签中设置scope
属性来指定作用域
- singleton:默认的.容器初始时创建Bean实例.在整个容器的生命周期内只创建这一个Bean
- prototype:容器初始化时不创建Bean实例.每次请求时创建一个新的实例
1. singleton
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 31 32 33 34 35 36 37
| package relation;
public class Address { private String city; private String street;
public Address() { System.out.println("Address' construction..."); }
@Override public String toString() { return "Address{" + "city='" + city + '\'' + ", street='" + street + '\'' + '}'; }
public void setCity(String city) { this.city = city; }
public void setStreet(String street) { this.street = street; } }
|
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
| package relation;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Address address = (Address) applicationContext.getBean("address"); Address address_1 = (Address) applicationContext.getBean("address"); System.out.println(address == address_1); } }
|
applicationContext.xml
1 2 3 4 5 6
| <?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 scope="singleton" id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/> </beans>
|
输出结果为:
1 2
| Address' construction... true
|
可见只是在容器初始化时创建了一次Bean,而后获取的Bean都是同一个对象
2. prototype
将上面的xml文件修改如下:
1 2 3 4 5 6
| <?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 scope="prototype" id="address" class="relation.Address" p:city="Beijing" p:street="NanJingLu"/> </beans>
|
而后运行,结果为:
1 2 3
| Address' construction... Address' construction... false
|
可见容器初始化时没有新建Bean对象,而是每次请求时创建一个新的Bean对象
使用外部属性文件
在配置文件中配置Bean时,有时需要在Bean的配置中混入系统部署的细节信息(例如文件路径,数据源配置信息等).而这些部署细节实际上需要和Bean配置相分离
Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中.可以在Bean配置文件中使用形式为${var}
的变量,PropertyPlaceholderConfigurer从属性文件中嘉爱属性,并使用这些属性来替换变量
Spring还允许在属性文件中使用${propName}
,以实现属性之间的相互引用
正常获取数据库连接的配置如下:
pom.xml引入c3p0和MySQL驱动:
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency>
|
applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="root"/> <property name="password" value="@SWZDL231100"/> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/wechat?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/> </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
| package relation;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource; import java.sql.SQLException;
public class Main { public static void main(String[] args) throws SQLException { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource dataSource = (DataSource) applicationContext.getBean("dataSource"); System.out.println(dataSource.getConnection()); } }
|
运行结果为
1
| com.mchange.v2.c3p0.impl.NewProxyConnection@27c6e487 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@49070868]
|
表示连接成功
但是此时数据库密码等都在applicationContext.xml中,不方便修改,可以将这些配置放在外部的配置文件中
新建配置文件名为DataSource.properties
1 2 3 4
| user=root password=@SWZDL231100 driverClass=com.mysql.cj.jdbc.Driver jdbcUrl=jdbc:mysql://localhost:3306/wechat?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
|
修改applicationContext.xml
为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?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.xsd">
<context:property-placeholder location="relation/DataSource.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${user}"/> <property name="password" value="${password}"/> <property name="driverClass" value="${driverClass}"/> <property name="jdbcUrl" value="${jdbcUrl}"/> </bean>
</beans>
|
运行结果相同
SpEL
SpEL:Spring表达式语言,是一个支持运行时查询和操作对象图的强大表达式语言
语法类似于EL:SpEL使用#{...}
作为定界符,所有在大括号中的字符都被认为是SpEL
SpEL为Bean的属性进行动态赋值提供了便利
通过SpEL可以实现:
- 通过Bean的id对Bean进行引用
- 调用方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
SpEL字面量(意义不大):
- 整数:
<property name = "count" value="#{5}"/>
- 小数:
<property name = "frequency" value="#{89.7}"/>
- 科学计数法:
<property name = "capacity" value="#{1e4}"/>
- String可以使用单引号或者双引号作为字符串的定界符号:
<property name = "name" value="#{'Chuck'}"/>
或者:<property name = "name" value='#{"Chuck"}'/>
- Boolean:
<property name="enabled" value="#{false}"/>
引用Bean、属性和方法
- 引用其他对象
- 引用其他对象的属性
- 调用其他方法,还可以链式操作
支持的运算符号
- 算数运算符:
+
,-
,*
,/
,%
,^
- 加号可拼接字符串
- 比较运算符:
<
,>
,==
,<=
,>=
,lt
,gt
,eg
,le
,ge
- 逻辑运算符:
and
,or
,not
- if-else运算符:
?:(tenmary),?:(Elvis)
- if-else的变体
- 正则表达式:matches
- 调用静态方法或静态属性:通过T()调用一个类的静态方法,他将返回一个Class Object,然后再调用相应的方法或属性
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 31 32 33 34 35 36 37 38 39 40 41
| package 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 46 47 48 49 50 51
| package spel;
public class Car { private double price; private String brand; private int typePerimeter;
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; }
public int getTypePerimeter() { return typePerimeter; }
public void setTypePerimeter(int typePerimeter) { this.typePerimeter = typePerimeter; }
@Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + ", typePerimeter=" + typePerimeter + '}'; } }
|
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
| package spel;
public class Person { private String name; private Car car; private String city; private String info;
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", car=" + car + ", city='" + city + '\'' + ", info='" + info + '\'' + '}'; }
public void setName(String name) { this.name = name; }
public void setCar(Car car) { this.car = car; }
public void setCity(String city) { this.city = city; }
public void setInfo(String info) { this.info = info; } }
|
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
| package spel;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spel/spel.xml"); Car car = (Car) applicationContext.getBean("car_1"); System.out.println(car);
Address address = (Address) applicationContext.getBean("address"); System.out.println(address);
Person person = (Person) applicationContext.getBean("person"); System.out.println(person); } }
|
spel.xml
1 2 3 4 5 6 7 8 9 10 11
| <?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="car_1" class="spel.Car" p:brand="Audi" p:price="300000" p:typePerimeter="#{T(Math).PI*80}"/> <bean id="address" class="spel.Address" p:city="HeFei" p:street="ShuangDun"/> <bean id="person" class="spel.Person" p:car="#{car_1}" p:city="#{address.city}" p:name="Sheng" p:info="#{car_1.price>10000? '金领':'白领'}"/> </beans>
|
运行结果:
1 2 3
| Car{brand='Audi', price=300000.0, typePerimeter=251} Address{city='HeFei', street='ShuangDun'} Person{name='Sheng', car=Car{brand='Audi', price=300000.0, typePerimeter=251}, city='HeFei', info='金领'}
|
注意:引用其他Bean的属性时,需要被引用的Bean的类中有getter方法或者要引用的属性是public的
Bean的生命周期
1. IOC容器中Bean的生命周期方法
SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean的生命周期的特定点执行定制的任务
1.1 SpringIOC容器对Bean的生命周期进行管理的过程
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其他Bean的引用
- 调用Bean的初始化方法
- Bean可以使用了
- 当容器关闭时,调用Bean的销毁方法
在Bean的声明里设置init-method
和destroy-method
属性,为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 30 31 32 33 34 35 36 37 38 39 40 41 42
| package cycle;
public class Car { private String brand;
public Car() { System.out.println("Car's constructor.."); }
@Override public String toString() { return "Car{" + "brand='" + 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..."); } }
|
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
| package cycle;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("cycle/cycle.xml"); Car car = (Car) applicationContext.getBean("car"); System.out.println(car); applicationContext.close();
} }
|
cycle.xml
1 2 3 4 5 6 7
| <?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="car" class="cycle.Car" init-method="init" destroy-method="destroy" p:brand="Audi"/> </beans>
|
运行结果为:
1 2 3 4 5
| Car's constructor.. setBrand... init... Car{brand='Audi'} destroy...
|
2. 创建Bean后置处理器
Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理
Bean后置处理器对IOC容器中的所有Bean实例逐一处理,而非单一实例.其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性
对Bean后置处理器而言,需要实现(org.springframework.bean.factory.comfig)
BeanPostProcessor接口,在初始化方法被调用前后,Spring将把每个Bean实例分别传递给上述接口的以上两个方法:
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其他Bean的引用
- 调用Bean的初始化方法
- Bean可以使用了
- 当容器关闭时,调用Bean的销毁方法
通过实例来说明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 30 31 32 33 34 35 36 37 38 39 40 41 42
| package cycle;
public class Car { private String brand;
public Car() { System.out.println("Car's constructor.."); }
@Override public String toString() { return "Car{" + "brand='" + 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..."); } }
|
PosrProcesser.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
| package cycle;
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;
public class PostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization\t" + bean + "\t" + beanName); return bean; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization\t" + bean + "\t" + beanName); return bean; } }
|
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
| package cycle;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("cycle/cycle.xml"); Car car = (Car) applicationContext.getBean("car"); System.out.println(car); applicationContext.close();
} }
|
cycle.xml
1 2 3 4 5 6 7 8 9
| <?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="car" class="cycle.Car" init-method="init" destroy-method="destroy" p:brand="Audi"/>
<bean class="cycle.PostProcessor"/> </beans>
|
运行结果为:
1 2 3 4 5 6 7
| Car's constructor.. setBrand... postProcessBeforeInitialization Car{brand='Audi'} car init... postProcessBeforeInitialization Car{brand='Audi'} car Car{brand='Audi'} destroy...
|