IOC & DI 配置Bean之bean的生命周期及bean的配置方式
Bean的生命周期
IOC 容器中 Bean 的生命周期方法
- Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务.
- 在 Bean 的声明里设置 init-method和destroy-method 属性, 为 Bean 指定初始化和销毁方法.
Car.java
package com.xyc.spring.cycle;
/**
*
* @ClassName: Car
* @Description:Spring IOC容器及生命周期测试
* @author: xyc
* @date: 2016年11月26日 下午4:25:23
*
*/
public class Car {
private String brand;
public void setBrand(String brand) {
System.out.println("Car setBrand.........");
this.brand = brand;
}
public void init(){
System.out.println("Car init...........");
}
public void destory(){
System.out.println("Car destory..........");
}
public Car() {
System.out.println("Car Contruator...");
}
@Override
public String toString() {
return "Car [brand=" + brand + "]";
}
}
<?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 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法. -->
<bean id="car" class="com.xyc.spring.cycle.Car" init-method="init" destroy-method="destory">
<property name="brand" value="BMW"></property>
</bean>
</beans>
ApplicationCycle.java
package com.xyc.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xyc.spring.cycle.Car;
/**
*
* @ClassName: ApplicationCycle
* @Description:测试spring IOC容器及生命周期
* @author: xyc
* @date: 2016年11月26日 下午4:30:05
*
*/
public class ApplicationCycle {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-cycle.xml");
Car car = (Car) context.getBean("car");
System.out.println(car);
//关闭IOC
context.close();
}
}
由此可以看出,Spring IOC 容器对 Bean 的生命周期进行管理的过程如下:
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 调用 Bean 的初始化方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
添加 Bean 后置处理器后 Bean 的生命周期
- Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
- Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.
- 对Bean 后置处理器而言, 需要实现 BeanPostProcessor接口. 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给BeanPostProcessor接口的两个方法:
MyBeanPostProcessor.java
package com.xyc.spring.cycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
*
* @ClassName: MyBeanPostProcessor
* @Description: Bean 后置处理器
* @author: xyc
* @date: 2016年11月26日 下午4:47:11
*
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("car".equals(beanName)){
System.out.println("postProcessBeforeInitialization: "+bean+"@"+beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization: "+bean+"@"+beanName);
Car car = new Car();
car.setBrand("SUV");
return car;
}
}
xml中配置:
<!--
实现BeanPostProcessor接口,并具体提供
Object postProcessBeforeInitialization(Object bean, String beanName) init-method之前被调用
Object postProcessAfterInitialization(Object bean, String beanName) init-method之后被调用
bean: bean实例本身
beanName: IOC 容器中配置bean的id
返回值:是具体返回给用户的那个Bean,注意可以在以上两个方法中修改返回的Bean,甚至可以返回一个全新的bean
-->
<!-- 配置bean的后置处理器:不需要配置id,IOC容器自动识别一个BeanPostProcessor -->
<bean class="com.xyc.spring.cycle.MyBeanPostProcessor"></bean>
运行结果:
由此可以看出,Spring IOC 容器对 Bean 的生命周期进行管理的过程:
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
- 调用 Bean 的初始化方法
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
Bean的配置方式
- 通过全类名(反射),通过反射的方式加载类的全路径,前面一直是这种方式.
- 通过工厂方法(静态工厂方法 & 实例工厂方法)
- FactoryBean
通过调用静态工厂方法创建 Bean
- 调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节.
- 要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法的名称. 最后, 使用 <constrctor-arg> 元素为该方法传递方法参数.
car.java
package com.xyc.spring.factory;
/**
*
* @ClassName: Car
* @Description:Bean的配置方式
* @author: xyc
* @date: 2016年11月27日 下午5:06:21
*
*/
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;
}
public Car(String brand, Double price) {
this.brand = brand;
this.price = price;
}
public Car() {
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
}
CarStaticFactory.java
package com.xyc.spring.factory;
import java.util.HashMap;
import java.util.Map;
/**
*
* @ClassName: CarStaticFactory
* @Description:静态工厂方法:直接调用某一个类的静态方法就可以返回Bean实例
* @author: xyc
* @date: 2016年11月27日 下午5:09:22
*
*/
public class CarStaticFactory {
private static Map<String,Car> map = new HashMap<String, Car>();
static{
map.put("BYD", new Car("BYD", 300000.00));
map.put("BMW", new Car("BMW", 500000.00));
}
public static Car getCar(String brand){
return map.get(brand);
}
}
xml中配置
<!-- 通过静态工厂的方式来配置bean,注意不是配置静态工厂方法实例,而是配置bean实例 -->
<!--
class: 指向静态工厂方法的全类名
factory-method:指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg 来配置参数
-->
<bean id="car1" class="com.xyc.spring.factory.CarStaticFactory" factory-method="getCar">
<constructor-arg value="BMW"></constructor-arg>
</bean>
通过调用实例工厂方法创建 Bean
- 实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里. 当客户端需要请求对象时, 只需要简单的调用该实例方法而不需要关心对象的创建细节.
- 要声明通过实例工厂方法创建的 Bean
- --在 bean 的 factory-bean 属性里指定拥有该工厂方法的 Bean
- --在 factory-method 属性里指定该工厂方法的名称
- --使用 construtor-arg 元素为工厂方法传递方法参数
CarInstanceFactory.java
package com.xyc.spring.factory;
import java.util.HashMap;
import java.util.Map;
/**
*
* @ClassName: CarInstanceFactory
* @Description:实例工厂方法:实例工厂的方法,即现需要创建工厂本身,再调用工厂的实例来返回bean 的实例
* @author: xyc
* @date: 2016年11月27日 下午5:22:00
*
*/
public class CarInstanceFactory {
private Map<String,Car> map;
public CarInstanceFactory() {
map = new HashMap<String, Car>();
map.put("BYD", new Car("BYD", 300000.00));
map.put("BMW", new Car("BMW", 300000.00));
}
public Car getCar(String brand){
return map.get(brand);
}
}
xml中配置:
<!-- 配置工厂实例 -->
<bean id="carInstanceFactory" class="com.xyc.spring.factory.CarInstanceFactory"></bean>
<!-- 通过实例工厂配置bean -->
<!--
factory-bean:指向实例工厂id
factory-method:指向实例工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg 来配置参数
-->
<bean id="car2" factory-bean="carInstanceFactory" factory-method="getCar">
<constructor-arg value="BYD"></constructor-arg>
</bean>
实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
- Spring 中有两种类型的 Bean, 一种是普通Bean, 另一种是工厂Bean, 即FactoryBean.
- 工厂 Bean 跟普通Bean不同, 其返回的对象不是指定类的一个实例, 其返回的是该工厂 Bean 的 getObject 方法所返回的对象
CarBeanFactory.java
package com.xyc.spring.factory;
import org.springframework.beans.factory.FactoryBean;
/**
*
* @ClassName: CarBeanFactory
* @Description:通过FactoryBean工厂创建bean
* @author: xyc
* @date: 2016年11月27日 下午5:46:52
*
*/
public class CarBeanFactory implements FactoryBean<Car>{
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
/**
*
* <p>Title: getObject</p>
* <p>Description: </p>
* @return 返回bean的对象
* @throws Exception
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Override
public Car getObject() throws Exception {
return new Car(brand, 300000.00);
}
/**
*
* <p>Title: getObjectType</p>
* <p>Description: </p>
* @return bean类型
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
@Override
public Class<?> getObjectType() {
return Car.class;
}
/**
*
* <p>Title: isSingleton</p>
* <p>Description: </p>
* @return 是否单例
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
@Override
public boolean isSingleton() {
return true;
}
}
<!-- 通过FactoryBean工厂配置Bean的实例
class:指向FactoryBean的实现类的全类名
property:指向FactoryBean的实现类的属性
实际返回的是FactoryBean 的getObject()方法返回的实例
-->
<bean id="car3" class="com.xyc.spring.factory.CarBeanFactory">
<property name="brand" value="BMW"></property>
</bean>