bean 的生命周期意思是指从 Bean 创建,到 Bean 初始化,再到销毁的过程
Spring IoC 容器管理 bean 的生命周期,我们可以自定义初始化和销毁方法,容器在 bean 进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
一、@Bean 指定初始化和销毁方法
1.1 创建实体类 Car,在实体类中创建初始化方法以及销毁方法
package org.example.pojo;
public class Car {
public Car(){
System.out.println("car constructor...");
}
public void initCar(){
System.out.println("car ... initCar...");
}
public void destroyCar(){
System.out.println("car ... destroyCar");
}
}
1.2 创建配置类,同时向容器中注入实体类 Car
在通过 @Bean 注解向容器中注入 Car 时,同时添加初始化和销毁方法。添加方法:在 @Bean 注解中新增 initMethod 和 destoryMethod
两个属性,用以指定需要添加的初始化和销毁方法。
package org.example.config;
import org.example.pojo.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class InitAndDestoryTestConfig {
@Scope
@Bean(initMethod = "initCar", destroyMethod = "destroyCar")
public Car car(){
return new Car();
}
}
1.3 测试方法
@Test
public void testInitAndDestroy(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(InitAndDestroyTestConfig.class);
System.out.println("容器创建完成......");
Object car = ac.getBean("car");
Object car1 = ac.getBean("car");
System.out.println(car);
System.out.println(car1);
System.out.println(car == car1);
ac.close();
}
测试结果:
再来测一下当 Scope 为 多实例时的情况:
将配置类中 @Scope 的 value 属性修改为 ”prototype“,测试方法不变,进行测试,测试结果如下:
1.4 总结
单实例 | 多实例 | |
---|---|---|
构造函数(对象创建)时间 | 在容器启动的时候创建对象 | 在每次获取的时候创建对象 |
初始化时间 | 对象创建完成,并赋值好,调用初始化方法 | 对象创建完成,并赋值好,调用初始化方法 |
销毁时间 | 在容器关闭的时候调用销毁方法 | 容器不会管理bean,故而容器不会调用销毁方法 |
二、InitializingBean 和 DisposableBean
2.1 接口定义
2.1.1 InitializingBean 接口定义
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
在容器对 bean 进行初始化时,如果该 bean 实现了InitializingBean 接口,将会调用接口中的 afterPropertiesSet() 方法,完成一些用户自定义的初始化操作。
2.1.2 DisposableBean 接口
public interface DisposableBean {
void destroy() throws Exception;
}
BeanFactory 将在单实例 bean 销毁时调用 destroy 方法。
2.1.3 案例
实体类 Car 实现InitializingBean 和 DisposableBean 接口
package org.example.pojo;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Car implements InitializingBean, DisposableBean {
public Car(){
System.out.println("car constructor...");
}
public void initCar(){
System.out.println("car ... initCar...");
}
public void destroyCar(){
System.out.println("car ... destroyCar");
}
@Override
public void destroy() throws Exception {
System.out.println("car......DisposableBean......destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("car......InitializingBean......afterPropertiesSet");
}
}
配置类以及测试方法保持不变,测试结果如下:
2.1.4 总结
当一个实体类中既通过 @Bean 注解指定了 initMethod 以及 destroyMethod,还实现了 InitializingBean 和 DisposableBean 接口,那么容器在初始化时会优先执行 InitializingBean 中的 afterPropertiesSet() 方法,而在销毁阶段,DisposableBean 中的 destroy 方法的执行顺序也是优先于 @Bean 注解指定的销毁方法的。
三、使用 JSR250
3.1 @PostConstruct 注解
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
标有 @PostConstruct 注解的方法,容器在 bean 创建完成并且属性赋值完成后,会调用该初始化方法。
3.2 @PreDestroy 注解
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
标有 @PreDestroy 注解的方法,会在容器销毁 bean 之前进行调用
3.3 案例
修改实体类 Car:
package org.example.pojo;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Car implements InitializingBean, DisposableBean {
public Car(){
System.out.println("car constructor...");
}
public void initCar(){
System.out.println("car ... initCar...");
}
public void destoryCar(){
System.out.println("car ... destoryCar");
}
@Override
public void destroy() throws Exception {
System.out.println("car......DisposableBean......destory");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("car......InitializingBean......afterPropertiesSet");
}
@PostConstruct
public void initPostConstruct(){
System.out.println("car......initPostConstruct......");
}
@PreDestroy
public void initPreDestroy(){
System.out.println("car......initPreDestroy......");
}
}
配置类以及测试方法不变,测试结果:
可以看出带有 @PostConstruct 注解和@PreDestroy 注解的方法其执行顺序要优先于其他两种方式。
四、使用 BeanPostProcessor 接口
4.1 接口介绍
BeanPostProcessor 是一个接口,它是 bean 的后置处理器,该接口会在 bean 初始化前后进行一些处理工作。
接口源码:
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
- postProcessBeforeInitialization 方法:在初始化之前工作
- postProcessAfterInitialization:在初始化之后工作
- 方法参数 bean:bean 实例
- 方法参数 beanName:bean 实例的名称
- 返回值:返回值为原始的 bean 实例或者经过包装后的 bean 实例,如果返回值为 null,后续的 BeanPostProcessor 将不会被执行。
4.2 案例
创建 MyBeanPostProcessor 类,实现 BeanPostProcessor 接口,同时将 MyBeanPostProcessor 类通过 @Component 注解注入到容器中。
package org.example.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization..." + beanName + "--->" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization..." + beanName + "--->" + bean);
return bean;
}
}
配置类 InitAndDestoryTestConfig 添加注解 @ComponentScan(“org.example.processor”),将 MyBeanPostProcessor 同过包扫描的方式注入到容器中。
package org.example.config;
import org.example.pojo.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("org.example.processor")
public class InitAndDestoryTestConfig {
@Bean(initMethod = "initCar", destroyMethod = "destoryCar")
public Car car(){
return new Car();
}
}
测试方法不变,测试结果如下:
4.3 总结
BeanPostProcessor 中的 postProcessBeforeInitialization 方法执行时间要先于其他三种方式,但是 postProcessAfterInitialization 方法与其他三种销毁方法是不一样的,该方法是在 bean 初始化完成之后执行,并不属于销毁方法。
五、总结
本节内容总共介绍了四种初始化方法,以及三种销毁方法,另外 BeanPostProcessor 中的 postProcessAfterInitialization 并不属于销毁方法,该方法是在 bean 初始化完成之后执行的。
四种初始化方法的执行时间优先顺序如下:
BeanPostProcessor 中的 postProcessBeforeInitialization > @PostConstruct 注解 > InitializingBean 接口中的 afterPropertiesSet 方法 > @Bean 注解中 initMethod 属性指定的初始化方法
三种销毁方法的执行时间优先顺序如下:
@PreDestroy 注解 > DisposableBean 接口中的 destroy 方法 > @Bean 注解中 destroyMethod 属性指定的初始化方法