L
L
LearnJava
Search…
SpringBean的生命周期

生命周期

对于普通的java对象,当new的时候创建对象,当它没有任何引用的时候被垃圾回收机制回收。而Spring Ioc容器托管的对象,它们的生命周期完全由容器控制。Spring Bean的声明周期如下:
整个生命周期流程如下:
  1. 1.
    Spring对Bean进行初始化(此时执行构造器)
  2. 2.
    Spring将值和Bean的引用注入Bean对应的属性中
  3. 3.
    如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName(String name)方法 (实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的
  4. 4.
    如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory方法并把BeanFactory容器实例作为参数传入。 (实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)
  5. 5.
    如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)方法,把应用上下文作为参数传入。 (作用与BeanFactory类似都是为了获取Spring容器,不同的是ApplicationContextAware继承自BeanFactory,所以除了BeanFactory的所有功能,还提供了很多其他强大功能 )
  6. 6.
    当经过上述几个步骤后,bean对象已经被正确构造,但如果你想要对象被使用前再进行一些自定义的处理,就可以通过BeanPostProcessor接口实现。 注意:这个接口作用于所有的Bean 该接口提供了两个函数:
    • postProcessBeforeInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。 这个函数会先于InitialzationBean执行,因此称为前置处理。 所有Aware接口的注入就是在这一步完成的。
    • postProcessAfterInitialzation( Object bean, String beanName ) 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean作任何处理。 这个函数会在InitialzationBean完成后执行,因此称为后置处理。
  7. 7.
    当BeanPostProcessor的前置处理完成后就会进入InitializingBean接口。
    这一阶段也可以在bean正式构造完成前增加我们自定义的逻辑,但它与前置处理不同,由于该函数并不会把当前bean对象传进来,因此在这一步没办法处理对象本身,只能增加一些额外的逻辑。 若要使用它,我们需要让bean实现该接口,并把要增加的逻辑写在该函数中。然后Spring会在前置处理完成后检测当前bean是否实现了该接口,并执行afterPropertiesSet函数。
    当然,Spring为了降低对客户代码的侵入性,给bean的配置提供了init-method属性,该属性指定了在这一阶段需要执行的函数名。Spring便会在初始化阶段执行我们设置的函数。init-method本质上仍然使用了InitializingBean接口。
  8. 8.
    经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁
  9. 9.
    如果Bean实现了DisposableBean接口,Spring将调用它的destory方法,作用与在配置文件中对Bean使用destory-method属性的作用一样,都是在Bean实例销毁前执行的方法。

BeanFactoryPostProcessor

BeanFactoryPostProcessor与BeanPostProcessor不同的是:
  1. 1.
    BeanFactoryPostProcessor在所有Bean初始化之前执行,也就是最开始的地方;
  2. 2.
    BeanFactoryPostProcessor只执行一次,而BeanPostProcessor在每个Bean生成周期期间都会执行;
BeanFactoryPostProcessor可以对Bean的配置元数据(XML中配置的bean的属性)进行处理。如果你需要在所有Bean初始化之前执行一段逻辑并且只执行一次,选择BeanFactoryPostProcessor在合适不过了。
使用示例:
public class Test implements BeanPostProcessor, BeanFactoryPostProcessor {
// 所有Bean初始化的时候都会执行
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("enter Test.postProcessBeforeInitialization, beanName:" + beanName);
return bean;
}
// 所有Bean初始化之前执行一次
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("enter Test.postProcessBeanFactory, beanName:" + configurableListableBeanFactory.getBeanDefinition("shareInterface").getBeanClassName());
}
}

SmartLifecycle

SmartLifecycle 在容器所有bean加载和初始化完毕执行。
有时候我们需要在Spring加载和初始化所有bean后,接着执行一些任务或者启动需要的异步服务,这样我们可以使用 SmartLifecycle 来做到。SmartLifecycle 是一个接口。当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)。除了start方法,其他方法的作用如下:
// 所有bean初始化完成后执行,只有isAutoStartup返回true才会被执行
public void start() {
}
// 该方法只对直接实现接口Lifecycle的类才起作用,对实现SmartLifecycle接口的类无效
// 方法stop()和方法stop(Runnable callback)的区别只在于,后者是SmartLifecycle子类的专属。
public void stop() {
}
// 只有该方法返回false时,start方法才会被执行。
// 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
public boolean isRunning() {
return false;
}
// true:执行start方法,false:不执行start方法(默认)
public boolean isAutoStartup() {
return false;
}
// 当isRunning方法返回true时,该方法才会被调用。
public void stop(Runnable callback) {
// 如果你让isRunning返回true,需要执行stop这个方法,那么就不要忘记调用callback.run()。
// 否则在你程序退出时,Spring的DefaultLifecycleProcessor会认为你这个TestSmartLifecycle没有stop完成,程序会一直卡着结束不了,等待一定时间(默认超时时间30秒)后才会自动结束。
// PS:如果你想修改这个默认超时时间,可以按下面思路做,当然下面代码是springmvc配置文件形式的参考,在SpringBoot中自然不是配置xml来完成,这里只是提供一种思路。
// <bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
// <!-- timeout value in milliseconds -->
// <property name="timeoutPerShutdownPhase" value="10000"/>
// </bean>
}
// 如果工程中有多个实现接口SmartLifecycle的类,则这些类的start的执行顺序按getPhase方法返回值从小到大执行。
// 例如:1比2先执行,-1比0先执行。 stop方法的执行顺序则相反,getPhase返回值较大类的stop方法先被调用,小的后被调用。
public int getPhase() {
return 0;
}

小技巧

// 1. 获取某个类的所有Bean实例的name
String[] beanNames = context.getBeanNamesForType(TestBean.class);
Copy link
On this page
生命周期
BeanFactoryPostProcessor
SmartLifecycle
小技巧