spring是java编程最常用的IoC框架,我们在平常的使用中会将用到的bean全部注入到spring的容器中,让spring帮助我们管理,在有些编码的场景中,我们需要人为的控制bean的生命周期,本文总结了几种控制spring中bean生命周期的方法,供大家参考。
如果需要控制一个bean的初始化和销毁,可以在对象中创建对应的方法,并用@Bean注入到spring中,这时候只需要指定@Bean的initMethod 和 destroyMethod到具体的方法即可,示例代码如下:
public class Car {
public Car(){
System.out.println("构造方法");
}
public void addOil(){
System.out.println("加油");
}
public void run(){
System.out.println("启动");
}
public void close(){
System.out.println("关闭熄火");
}
}
@Configuration
public class LifycycleConfig {
@Bean(initMethod = "addOil", destroyMethod = "close")
public Car car() {
return new Car();
}
}
public class LifecycleTest {
@Test
public void testBeanAnnotationConfig() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifycycleConfig.class);
System.out.println("-----------IoC容器创建完成------------------");
Car car = app.getBean(Car.class);
car.run();
app.close();
}
}
测试结果如下:
构造方法
加油
-----------IoC容器创建完成------------------
启动
五月 07, 2023 5:09:52 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@161cd475: startup date [Sun May 07 17:09:51 CST 2023]; root of context hierarchy
关闭熄火
从上面的结果中可以看出,spring在创建完Car对象后,自动调用了initMethod 指定的addOil方法,在spring容器关闭的时候,自动调用了destroyMethod 指定的close方法。这里有一点需要注意,spring关闭容器需要显示的调用close()方法,我们平常的指点点击关闭按钮或者用kill 的方式,是没法调用到close()方法的,自然也就调用不到我们的destroy方法,所以一些重要的销毁逻辑不能写在依赖spring的destroy方法的逻辑中。
可以让bean实现InitializingBean和DisposableBean接口,并实现对应的初始化或者销毁方法,这样将这个bean注入到spring容器中后,spring会按照指定的方法来实现生命周期的管理。示例代码如下:
public class Train implements InitializingBean, DisposableBean {
public void run(){
System.out.println("启动");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化");
}
}
@Bean
public Train train() {
return new Train();
}
@Test
public void testInitializingBeanAndDisposableBean() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifycycleConfig.class);
System.out.println("-----------IoC容器创建完成------------------");
Train train = app.getBean(Train.class);
train.run();
app.close();
}
测试结果如下:
初始化
-----------IoC容器创建完成------------------
启动
五月 07, 2023 5:18:27 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@161cd475: startup date [Sun May 07 17:18:26 CST 2023]; root of context hierarchy
销毁
可以在Bean对应的方法上加上@PostConstruct和@PreDestroy注解,这样在构造方法调用完成,spring会调用加了@PostConstruct注解的方法,在spring容器要销毁的时候,会调用加了@PreDestroy注解的方法。示例代码如下:
public class AirPlane {
public void fly(){
System.out.println("起飞");
}
@PostConstruct
public void init(){
System.out.println("启动前检查");
}
@PreDestroy
public void stop(){
System.out.println("降落停机");
}
}
@Bean
public AirPlane airPlane() {
return new AirPlane();
}
@Test
public void testPostConstructAndPreDestroy() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifycycleConfig.class);
System.out.println("-----------IoC容器创建完成------------------");
AirPlane airPlane = app.getBean(AirPlane.class);
airPlane.fly();
app.close();
}
测试结果如下:
启动前检查
-----------IoC容器创建完成------------------
起飞
五月 07, 2023 5:24:25 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@161cd475: startup date [Sun May 07 17:24:25 CST 2023]; root of context hierarchy
降落停机
org.springframework.beans.factory.config.BeanPostProcessor接口是spring中一个非常重要的接口,看过源码的同学应该很清楚这个接口,因为这是spring中AOP等功能实现的基础,代理类就是在这个接口的方法中加入进去的,这个接口主要有两个方法,这两个方法是在初始化bean前后来调用的:接口会传进来bean的名称和创建的对象,然后经过处理后再返回一个新的对象,这样就可以在这里轻松加入代理对象。
BeanPostProcessor接口具体来说无法实现像前面中自动销毁的逻辑,但是可以实现在初始化前后增加功能的逻辑,当然也就可以调用具体的方法。我们这里仅示例一下这个接口的调用过程:
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization beanName="+ beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization beanName="+ beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
@Bean
public Bird bird() {
return new Bird();
}
@Bean
public BeanPostProcessor myBeanPostProcessor(){
return new MyBeanPostProcessor();
}
@Test
public void testBeanPostProcessor() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifycycleConfig.class);
System.out.println("-----------IoC容器创建完成------------------");
Bird bird = app.getBean(Bird.class);
app.close();
}
测试结果:
postProcessBeforeInitialization beanName=org.springframework.context.event.internalEventListenerProcessor
postProcessAfterInitialization beanName=org.springframework.context.event.internalEventListenerProcessor
postProcessBeforeInitialization beanName=org.springframework.context.event.internalEventListenerFactory
postProcessAfterInitialization beanName=org.springframework.context.event.internalEventListenerFactory
bird 构造方法
postProcessBeforeInitialization beanName=bird
postProcessAfterInitialization beanName=bird
-----------IoC容器创建完成------------------
从上面测试结果中可以看出,spring会将所有创建的对象在初始化前后全部传给MyBeanPostProcessor 对象,让其对创建的对象进行修改,这种设计思路,使得我们给spring中的bean增加新的功能成为了一种可能,很好的支持了功能的扩展性,值得我们好好研究和借鉴。
后记
个人总结,欢迎转载、评论、批评指正