ioc 容器中的bean的生命周期详解
- Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务
Spring IOC 容器对 Bean 的生命周期进行管理的过程:
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 调用 Bean 的初始化方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法
- 代码说明:
- 创建一个bean
public class Car {
private String name;
public Car() {
System.out.println("car has been created");
}
public void setName(String name) {
System.out.println("set name");
this.name = name;
}
public void carInit() {
System.out.println("car init !");
}
public void carDestroy() {
System.out.println("car destroy !");
}
@Override
public String toString() {
return "Car [name=" + name + "]";
}
}
- beans-lifeCircle.xml
<!-- 创建car这个bean的初始化方法和销毁方法 -->
<bean id="car" class="com.zc.cris.beans.lifeCircle.Car" init-method="carInit" destroy-method="carDestroy">
<property name="name" value="法拉利"></property>
</bean>
- 测试代码
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans-lifeCircle.xml");
System.out.println(context.getBean("car"));
//关闭ioc容器
context.close();
}
console:
什么是bean的后置处理器
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理,对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性
对Bean 后置处理器而言, 需要实现 beanPostProcessor 接口. 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的两个特定方法
- 测试代码如下:
- 自定义 MyCarPostProcess 类实现 BeanPostProcessor 接口
public class MyCarPostProcess implements BeanPostProcessor {
//bean的init方法前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization-----"+bean+"----------"+beanName);
//可以对bean进行过滤作用
// if("car".equals(beanName)) {
// ....
// }
return bean;
}
//bean的init方法之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization-----"+bean+"----------"+beanName);
//使用后置处理器进行bean的偷梁换柱
Car car = new Car();
car.setName("宾利");
return car;
}
}
- beans-lifeCircle.xml
<!-- 注册bean的后置处理器
实现BeanPostProcessor的接口:
1. Object postProcessBeforeInitialization(Object bean, String beanName)
在init-method方法之前调用
2. Object postProcessAfterInitialization(Object bean, String beanName)
在init-method方法之后调用
bean:bean实例本身
beanName:ioc 容器配置的bean的名字(id)
返回值:实际返回给用户的bean~~~~~可以在以上两个方法里面对bean进行处理,设置偷梁换柱!
-->
<!-- 不需要配置id属性,ioc容器自动识别为BeanPostProcessor -->
<bean class="com.zc.cris.beans.lifeCircle.MyCarPostProcess"></bean>
- 测试代码同上,不贴了
console:
- 添加 Bean 后置处理器后 Bean 的生命周期
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 将 Bean 实例传递给 Bean 后置处理器的postProcessBeforeInitialization 方法
- 调用 Bean 的初始化方法
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
- Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
通过调用实例工厂方法创建bean
除了在spring的bean配置文件中使用bean的全路径来创建bean,还可以使用工厂来创建bean(主要是应用在第三方框架整合方面)
使用静态工厂方法创建bean
- 调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节
代码解释:
- javaBean
public class Car {
private String name;
private Double price;
- staticFactory.java
//静态工厂方法:直接调用静态工厂的静态方法就可以返回一个bean的实例对象
public class StaticFactory {
private static Map<String, Car> map = new HashMap<>();
static{
map.put("奥迪", new Car("奥迪", 1234567D));
map.put("保时捷", new Car("保时捷", 23456789D));
}
public static Car getCar(String name) {
return map.get(name);
}
}
- beans-factory.xml
<!-- 通过静态工厂方法来配置bean,而是配置静态工厂实例
class属性:指向静态工厂的全类名
factory-method:指向静态工厂的静态方法的名字
constructor-arg:如果工厂的静态方法需要传入参数,则使用 constructor-arg 传入特定的参数
-->
<bean id="car" class="com.zc.cris.beans.factory.StaticFactory"
factory-method="getCar">
<constructor-arg value="保时捷"></constructor-arg>
</bean>
- TestBeanFactory.java
@Test
void testStaticFactory() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-factory.xml");
Object bean = context.getBean("car");
System.out.println(bean);
}
console:
使用实例工厂方法创建bean
- 实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里. 当客户端需要请求对象时, 只需要简单的调用该实例方法而不需要关心对象的创建细节
代码解释:
- Factory.java
//实例工程的方法:先创建工厂本身,再调用工厂实例的普通方法来返回bean的实例
public class Factory {
private Map<String, Car> cars = null;
public Factory() {
this.cars = new HashMap<>();
this.cars.put("法拉利", new Car("法拉利", 123D));
this.cars.put("帕拉梅拉", new Car("帕拉梅拉", 1321D));
}
public Car getCar(String name) {
return this.cars.get(name);
}
}
- factory.xml
<!-- 配置实例工厂 -->
<bean id="carFactory" class="com.zc.cris.beans.factory.Factory"></bean>
<!-- 通过实例工厂的方法来配置bean -->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="帕拉梅拉"></constructor-arg>
</bean>
- TestBeanFactory.java
@Test
void testFactory() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-factory.xml");
Object bean = context.getBean("car2");
System.out.println(bean);
}
console:
除了自定义工厂,以及调用全类名的方法外,spring还为我们提供了FactoryBean接口来创建bean
实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
Spring 中有两种类型的 Bean, 一种是普通Bean, 另一种是工厂Bean, 即FactoryBean
工厂 Bean 跟普通Bean不同, 其返回的对象不是指定类的一个实例, 其返回的是该工厂 Bean 的 getObject 方法所返回的对象
- 后面当我们需要使用spring提供的quartz工具或者其他工具bean的时候就会以这种方式获取bean实例
实例代码:
//自定义的factoryBean需要实现spring框架为我们提供的接口 FactoryBean
public class CarFactoryBean implements FactoryBean<Car>{
private String carName;
public void setCarName(String carName) {
this.carName = carName;
}
//返回bean的对象
@Override
public Car getObject() throws Exception {
Car car = new Car();
car.setName(carName);
return car;
}
//返回bean的类型
@Override
public Class<?> getObjectType() {
return Car.class;
}
//返回car这个bean是否是单例的
@Override
public boolean isSingleton() {
return true;
}
}
- beans-beanFactory.xml
<!--
通过 自定义FactoryBean的实现类来配置bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean 的属性
实际返回的bean实例其实是FactoryBean 的getObject()方法返回的实例!
-->
<bean id="car" class="com.zc.cris.beans.factoryBean.CarFactoryBean">
<property name="carName" value="阿斯顿马丁"></property>
</bean>
- 测试
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-beanFactory.xml");
Object bean = context.getBean("car");
System.out.println(bean);
}
}
console: