简介
Spring中Bean容器的生命周期。
首先明确一点,并非Spring容器中所有的Bean都有生命周期行为,只有接受容器管理生命周期的Bean才具有生命周期行为;而单例(Singleton)Bean接受容器管理,非单例(non-singleton)Bean在实例化后,完全交给了客户端代码管理,容器不再跟踪其生命周期,每次客户请求,容器都会创建一个新的实例,所以Spring容易无法知晓Bean何时销毁。
Bean容器的生命周期。其实上图有个节点没有画出,就是在实例化所有Bean之前会执行BeanFactoryPostProcessors
。
实例化
从图中,我们可以看到实例化Bean的顺序:
- 构造函数实例化。
- 设置属性值(ioc)。
- 如果该Bean实现
BeanNameAware
接口,调用Bean中的BeanNameAware#setBeanName()
。 - 如果该Bean实现
BeanFactoryAware
接口,调用Bean中的BeanFactoryAware#setBeanFactory()
。 - 调用
BeanPostProcessors#postProcessBeforeInitialization()
。 - 如果该Bean实现
InitializingBean
接口,调用Bean中的afterPropertiesSet()
。 - 调用Bean中的
init-method
,通常是在配置Bean的时候指定init-method
,例如:<bean class="beanClass" init-method="init"></bean>
。 - 调用
BeanPostProcessors#postProcessAfterInitialization()
。销毁
销毁Bean的顺序: - 在指定方法上加上
@PreDestroy
注解来制定该方法是在销毁之前调用。 - 通过实现
DisposableBean
接口来定制销毁之前的操作方法。 - 通过
<bean>
元素的destroy-method
属性指定销毁之前调用的操作方法。
如果该Bean是单例的,则当容器销毁并且该Bean实现DisposableBean
接口的时候,调用destory()
;如果该Bean是prototype,则将准备好的Bean提交给调用者,后续不再管理该Bean的生命周期。
程序
例1
内容:A类中有B类的引用,A类实例化的时候,B类也实例化好,init-method
最后执行。
A类
1 | package test; |
B类
1 | package test; |
Spring配置
1 | <bean id="a" class="test.A" init-method="initA"></bean> |
控制台
1 | A initialed |
例2
xml配置方式
上面顺序第6和第7条。先执行afterPropertiesSet()
,再执行init()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package test;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.InitializingBean;
public class AnotherDemoBean implements InitializingBean {
//初始化之后执行
@PostConstruct
public void postConstruct() {
System.out.println("AnotherDemoBean: postConstruct-method");
}
//xml配置里初始化执行
public void init() {
System.out.println("AnotherDemoBean: init-method");
}
//重载InitializingBean的方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("AnotherDemoBean: after properties set!");
}
}
Spring XML配置
1 | <bean class="test.AnotherDemoBean" init-method="init"></bean> |
控制台
1 | AnotherDemoBean: postConstruct-method |
注解方式
1 | package test; |
Spring XML
1 | <context:component-scan base-package="test"></context:component-scan> |
控制台1
2
3
4DemoBean: beanName aware, [name=demoBean]
DemoBean: beanFactory aware, [beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26aa4a14: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,demoBean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,propertyConfigurer,abstractBaseDao,crawlerService,erShouFangService,historyPriceService,crawlerPageDao,erShouFangDao,historyPriceDao,wenZhangDao,zuFangDao,wenZhangService,zuFangService,wubaErShouFangServer,xmfishNewsServer,_4399NewsServer,xmfishESFServer,com.amoyz.util.ContextUtil#0,fcJobTask,wzJobTask,fc_min30_server,fangchanCrawler30min,jobTrigger_FangChan_30min,wz_min5_server,wenzhangCrawler5min,jobTrigger_Wenzhang_5min,scheduler,mongo,org.springframework.beans.factory.config.CustomEditorConfigurer#0,org.springframework.beans.factory.config.CustomEditorConfigurer#1,org.springframework.beans.factory.config.CustomEditorConfigurer#2,mongoDbFactory,mongoTemplate,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy]
DemoBean: init-method
DemoBean: after properties set!
XML中指定Init-method,@PostConstruct注解方法哪个先执行
根据上一个例子结果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21AnotherDemoBean: postConstruct-method
AnotherDemoBean: after properties set!
AnotherDemoBean: init-method
```
`PostConstruct`先执行,`Init-method`最后执行,跟踪源码得知这个类`CommonAnnotationBeanPostProcessor`,从命名上,我们就可以得到某些信息——这是一个`BeanPostProcessor`。想到什么?在也谈Spring容器的生命周期中,我们提到过`BeanPostProcessor#postProcessBeforeInitialization`是在Bean生命周期中`afterPropertiesSet`和`init-method`之前执被调用的。再次观察`CommonAnnotationBeanPostProcessor`这个类,它继承自`InitDestroyAnnotationBeanPostProcessor`。`InitDestroyAnnotationBeanPostProcessor`顾名思义,就是在Bean初始化和销毁的时候所作的一个前置/后置处理器。
通过查看`InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization()`
```` java
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Couldn't invoke init method", ex);
}
return bean;
}
`
查看findLifecycleMetadata()
,跟踪到buildLifecycleMetadata()
中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25private LifecycleMetadata buildLifecycleMetadata(final Class clazz) {
final LifecycleMetadata newMetadata = new LifecycleMetadata();
final boolean debug = logger.isDebugEnabled();
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
if (initAnnotationType != null) {
if (method.getAnnotation(initAnnotationType) != null) {
newMetadata.addInitMethod(method);
if (debug) {
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
}
if (destroyAnnotationType != null) {
if (method.getAnnotation(destroyAnnotationType) != null) {
newMetadata.addDestroyMethod(method);
if (debug) {
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
}
}
});
return newMetadata;
}
在这里会去判断某方法有没有被initAnnotationType/destroyAnnotationType
注释,如果有,则把方法添加到init/destroy
队列中,后续一一执行。@PostConstruct
注解后的方法在BeanPostProcessor
前置处理器中就被执行,所以当然要先于InitializingBean
和init-method
执行。