前言
Spring Bean 的生命週期在整個 Spring 中佔有很重要的位置,掌握這些可以加深對 Spring 的理解。
首先看下生命週期圖:
再談生命週期之前有一點需要先明確:
Spring 只幫我們管理單例模式 Bean 的完整生命週期,對於 prototype 的 bean ,Spring 在建立好交給使用者之後則不會再管理後續的生命週期。
註解方式
在 bean 初始化時會經歷幾個階段,首先可以使用註解 @PostConstruct
, @PreDestroy
來在 bean 的建立和銷燬階段進行呼叫:
@Component
public class AnnotationBean {
private final static Logger LOGGER = LoggerFactory.getLogger(AnnotationBean.class);
@PostConstruct
public void start(){
LOGGER.info("AnnotationBean start");
}
@PreDestroy
public void destroy(){
LOGGER.info("AnnotationBean destroy");
}
}
複製程式碼
InitializingBean, DisposableBean 介面
還可以實現 InitializingBean,DisposableBean
這兩個介面,也是在初始化以及銷燬階段呼叫:
@Service
public class SpringLifeCycleService implements InitializingBean,DisposableBean{
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycleService.class);
@Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("SpringLifeCycleService start");
}
@Override
public void destroy() throws Exception {
LOGGER.info("SpringLifeCycleService destroy");
}
}
複製程式碼
自定義初始化和銷燬方法
也可以自定義方法用於在初始化、銷燬階段呼叫:
@Configuration
public class LifeCycleConfig {
@Bean(initMethod = "start", destroyMethod = "destroy")
public SpringLifeCycle create(){
SpringLifeCycle springLifeCycle = new SpringLifeCycle() ;
return springLifeCycle ;
}
}
public class SpringLifeCycle{
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycle.class);
public void start(){
LOGGER.info("SpringLifeCycle start");
}
public void destroy(){
LOGGER.info("SpringLifeCycle destroy");
}
}
複製程式碼
以上是在 SpringBoot 中可以這樣配置,如果是原始的基於 XML 也是可以使用:
<bean class="com.crossoverjie.spring.SpringLifeCycle" init-method="start" destroy-method="destroy">
</bean>
複製程式碼
來達到同樣的效果。
實現 *Aware 介面
*Aware
介面可以用於在初始化 bean 時獲得 Spring 中的一些物件,如獲取 Spring 上下文
等。
@Component
public class SpringLifeCycleAware implements ApplicationContextAware {
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycleAware.class);
private ApplicationContext applicationContext ;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext ;
LOGGER.info("SpringLifeCycleAware start");
}
}
複製程式碼
這樣在 springLifeCycleAware
這個 bean 初始化會就會呼叫 setApplicationContext
方法,並可以獲得 applicationContext
物件。
BeanPostProcessor 增強處理器
實現 BeanPostProcessor 介面,Spring 中所有 bean 在做初始化時都會呼叫該介面中的兩個方法,可以用於對一些特殊的 bean 進行處理:
@Component
public class SpringLifeCycleProcessor implements BeanPostProcessor {
private final static Logger LOGGER = LoggerFactory.getLogger(SpringLifeCycleProcessor.class);
/**
* 預初始化 初始化之前呼叫
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("annotationBean".equals(beanName)){
LOGGER.info("SpringLifeCycleProcessor start beanName={}",beanName);
}
return bean;
}
/**
* 後初始化 bean 初始化完成呼叫
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("annotationBean".equals(beanName)){
LOGGER.info("SpringLifeCycleProcessor end beanName={}",beanName);
}
return bean;
}
}
複製程式碼
執行之後觀察結果:
018-03-21 00:40:24.856 [restartedMain] INFO c.c.s.p.SpringLifeCycleProcessor - SpringLifeCycleProcessor start beanName=annotationBean
2018-03-21 00:40:24.860 [restartedMain] INFO c.c.spring.annotation.AnnotationBean - AnnotationBean start
2018-03-21 00:40:24.861 [restartedMain] INFO c.c.s.p.SpringLifeCycleProcessor - SpringLifeCycleProcessor end beanName=annotationBean
2018-03-21 00:40:24.864 [restartedMain] INFO c.c.s.aware.SpringLifeCycleAware - SpringLifeCycleAware start
2018-03-21 00:40:24.867 [restartedMain] INFO c.c.s.service.SpringLifeCycleService - SpringLifeCycleService start
2018-03-21 00:40:24.887 [restartedMain] INFO c.c.spring.SpringLifeCycle - SpringLifeCycle start
2018-03-21 00:40:25.062 [restartedMain] INFO o.s.b.d.a.OptionalLiveReloadServer - LiveReload server is running on port 35729
2018-03-21 00:40:25.122 [restartedMain] INFO o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup
2018-03-21 00:40:25.140 [restartedMain] INFO com.crossoverjie.Application - Started Application in 2.309 seconds (JVM running for 3.681)
2018-03-21 00:40:25.143 [restartedMain] INFO com.crossoverjie.Application - start ok!
2018-03-21 00:40:25.153 [Thread-8] INFO o.s.c.a.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3913adad: startup date [Wed Mar 21 00:40:23 CST 2018]; root of context hierarchy
2018-03-21 00:40:25.155 [Thread-8] INFO o.s.j.e.a.AnnotationMBeanExporter - Unregistering JMX-exposed beans on shutdown
2018-03-21 00:40:25.156 [Thread-8] INFO c.c.spring.SpringLifeCycle - SpringLifeCycle destroy
2018-03-21 00:40:25.156 [Thread-8] INFO c.c.s.service.SpringLifeCycleService - SpringLifeCycleService destroy
2018-03-21 00:40:25.156 [Thread-8] INFO c.c.spring.annotation.AnnotationBean - AnnotationBean destroy
複製程式碼
直到 Spring 上下文銷燬時則會呼叫自定義的銷燬方法以及實現了 DisposableBean
的 destroy()
方法。
號外
最近在總結一些 Java 相關的知識點,感興趣的朋友可以一起維護。