通常,bean的初始化和销毁方法我们有三个地方可以入手,分别是:

  1. 自定义初始化,销毁方法
  2. 实现spring提供的InitializingBean(初始化逻辑),DisposableBean(销毁逻辑)接口
  3. 实现spring提供的BeanPostProcessor接口,实现其postProcessBeforeInitialization方法来执行在初始化之前的操作,实现postProcessAfterInitialization方法来执行初始化之后的操作。

bean的生命周期:bean创建---初始化----销毁的过程

下面分别介绍上面提到的三种和初始化,销毁相关的接口,方法

 

1.自定义初始化,销毁方法

容器管理bean的生命周期:我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法

构造(对象创建):

  • 单实例:在容器启动的时候创建对象
  • 多实例:在每次获取的时候创建对象

销毁:

  • 单实例:容器关闭的时候
  • 多实例:容器不会管理这个bean;容器不会调用销毁方法,如果需要,自己手动调用销毁方法。

在xml配置中,可以通过init-method和destory-method指定初始化方法和销毁方法。该方法必须没有参数,但是可以抛出异常。

在现在流行的注解配置方式中,可以通过@Bean(initMethod="init",destroyMethod="destory")的方式指定bean的初始化方法和销毁方法。

定义Toyota类,然后定义两个方法,一个是我们想作为初始化方法的init方法,一个是我们想作为销毁方法的destory方法。

public class Toyota {

	public Toyota() {
		System.out.println("Toyota constructor...");
	}

	public void init() {
		System.out.println("Toyota ... init...");
	}

	public void detory() {
		System.out.println("Toyota ... destory...");
	}
}

将Toyota添加到配置类中

@Configuration
public class LifeCycleConfig {

	@Bean(initMethod="init",destroyMethod="detory")
	public Toyota toyota(){
		return new Toyota();
	}
}

测试并打印容器中的bean信息:

	@Test
	public void testCar() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
		printBeans(context);
		context.close();
	}
	private void printBeans(ApplicationContext context) {
		String[] defBeans = context.getBeanDefinitionNames();
		for (String name : defBeans) {
			System.out.println(name);
		}

	}

执行查看结果:

【spring系列】之6:bean的初始化和销毁方法

可以看到,在容器启动时,执行了Toyota的无参构造方法,然后紧接着执行了自定义bean的初始化方法init方法。

在容器关闭时,执行了自定义bean的销毁方法destory方法。

这里需要注意的是:@Bean默认是单例的,如果将scope改为多实例的,那执行结果就不是这样了,请看下面的代码:

@Configuration
public class LifeCycleConfig {

	@Bean(initMethod = "init", destroyMethod = "detory")
	@Scope("prototype")
	public Toyota toyota() {
		return new Toyota();
	}
}

执行的结果如下:

【spring系列】之6:bean的初始化和销毁方法

可以看到,容器启动时,并没有实例化和初始化Toyota对象,在容器关闭时,也没有调用destory方法。

此时,我们可以大胆猜测(肯定),只有单例的bean,在容器创建时才会实例化,并执行初始化方法,在容器关闭时执行销毁方法。对于多实例bean,只有在创建bean的时候才会实例化并初始化方法,如果要执行多实例bean的销毁方法,需要我们自己手动去调用。

	@Test
	public void testCar() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
		printBeans(context);
		context.getBean("toyota");
		context.close();
	}

	private void printBeans(ApplicationContext context) {

		String[] defBeans = context.getBeanDefinitionNames();
		for (String name : defBeans) {
			System.out.println(name);
		}

	}
}

【spring系列】之6:bean的初始化和销毁方法

 

2.实现spring提供的InitializingBean(初始化逻辑),DisposableBean(销毁逻辑)接口

通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);

我们还是在之前的Toyota类代码上继续我们的代码编写

public class Toyota implements InitializingBean, DisposableBean {

	public Toyota() {
		System.out.println("Toyota constructor...");
	}

	public void init() {
		System.out.println("define....Toyota ... init...");
	}

	public void detory() {
		System.out.println("define....Toyota ... detory...");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("DisposableBean....Toyota ... destroy...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("InitializingBean....Toyota ... afterPropertiesSet...");
	}
}

实现了InitializingBean接口,我们需要重写afterPropertiesSet方法,同样,实现了DisposableBean接口,我们需要重写destroy方法。既然用了这两个接口,那我们就一起看一下这两个接口的源码以及说明吧:

InitializingBean:

【spring系列】之6:bean的初始化和销毁方法

看源码的注释,我们知道,afterPropertiesSet的调用时机是在beanFactory(bean工厂)实例化bean后,将所有的属性值设置完毕之后,才会调用该接口方法。通过方法的申明,我们可以发现,该方法是一个无参方法,同时,在调用过程中可以抛出异常。

同样,我们看一下DisposableBean接口的源码:

【spring系列】之6:bean的初始化和销毁方法

通过源码,我们可以知道,destory方法的调用时机是在beanFactory关闭且bean为单例的对象时触发。通过注释,也可以发现,该方法可以抛出异常,但是异常并不会重复抛出,这样是为了保证其他的bean也可以释放他们自己的资源。

好了,插曲先到这,我们继续看我们的Toyota类,看看调用时会发生什么情况。

首先看当Toyota为单例时的执行结果:

【spring系列】之6:bean的初始化和销毁方法

可以看到,

  • 初始化过程:容器先调用了Toyota的无参构造方法来实例化Toyota对象实例,接着执行了InitialiaingBean的初始化方法afterPropertiesSet()方法,最后才执行我们自定义的init初始化方法。
  • 销毁过程:同样,容器也是先执行了DisposableBean的destory方法,然后才执行了我们自定义的destory销毁方法。

再看一下Toyota为多实例的执行结果:

【spring系列】之6:bean的初始化和销毁方法

可以看到,多实例初始化方法的执行顺序和单例是一样的,但是并没有执行销毁方法,不管是自定义的还是DisposableBean的销毁方法。

3.JSR250;@PostConstruct,@PreDestroy执行初始化和销毁方法

可以使用JSR250:

  • @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法,
  • @PreDestroy:在容器销毁bean之前通知我们进行清理工作

还是通过我们的代码来看问题,继续在上面的Toyota代码上修改:

public class Toyota implements InitializingBean, DisposableBean {

	public Toyota() {
		System.out.println("Toyota constructor...");
	}

	public void init() {
		System.out.println("define....Toyota ... init...");
	}

	public void detory() {
		System.out.println("define....Toyota ... detory...");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("DisposableBean....Toyota ... destroy...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("InitializingBean....Toyota ... afterPropertiesSet...");
	}

	@PostConstruct
	public void PostConstruct() {
		System.out.println("JSR250....PostConstruct....Toyota ... PostConstruct...");
	}

	@PreDestroy
	public void PreDestroy() {
		System.out.println("JSR250....PreDestroy....Toyota ... PreDestroy...");
	}
}

先查看Toyota为单例时的执行结果:

【spring系列】之6:bean的初始化和销毁方法

可以看到:

  • 初始化方法的执行顺序:先执行Toyota的无参构造方法产生兑现故事里,再执行JSR250的PostConstruct初始化方法,接着执行InitializingBean的afterPropertiesSet初始化方法,最后执行我们自定义的init初始化方法。
  • 销毁方法的执行顺序:和初始化方法一样,先执行JSR250的PerDestory销毁方法,再执行DisposableBean的destory方法,最后执行我们自定义的destory销毁方法。

再查看Toyota为多实例时的执行结果:

【spring系列】之6:bean的初始化和销毁方法

可以看到,初始化顺序和单例时是一样的顺序,但是并没有执行销毁方法,如果需要执行销毁方法,需要我们手动调用执行。

 

4.实现spring提供的BeanPostProcessor接口

接下来看最后一个BeanPostProcessor借口。

我们继续在之前的代码上修改:

public class Toyota implements InitializingBean, DisposableBean, BeanPostProcessor {

	public Toyota() {
		System.out.println("Toyota constructor...");
	}

	public void init() {
		System.out.println("define....Toyota ... init...");
	}

	public void detory() {
		System.out.println("define....Toyota ... detory...");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("DisposableBean....Toyota ... destroy...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("InitializingBean....Toyota ... afterPropertiesSet...");
	}

	@PostConstruct
	public void PostConstruct() {
		System.out.println("JSR250....PostConstruct....Toyota ... PostConstruct...");
	}

	@PreDestroy
	public void PreDestroy() {
		System.out.println("JSR250....PreDestroy....Toyota ... PreDestroy...");
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("BeanPostProcessor....postProcessBeforeInitialization....Toyota... postProcessBeforeInitialization...");
		return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("BeanPostProcessor....postProcessAfterInitialization....Toyota  ... postProcessAfterInitialization...");
		return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
	}

}

直接观察代码,会发现BeanPostProcessor的初始化方法postProcessBeforeInitialization有返回类型Object,

销毁方法postProcessAfterInitialization也有返回类型Object,同时两个方法都可以抛出BeansException异常。

 

 

 

 

遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,

一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization

BeanPostProcessor原理:populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值

initializeBean
 {
  applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
  applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }

 

4)、BeanPostProcessor【interface】:bean的后置处理器;

在bean初始化前后进行一些处理工作;

postProcessBeforeInitialization:在初始化之前工作

postProcessAfterInitialization:在初始化之后工作

Spring底层对 BeanPostProcessor 的使用;

bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;

 

相关文章: