spring 声明周期钩子方法
Posted QQ_851228082
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring 声明周期钩子方法相关的知识,希望对你有一定的参考价值。
spring bean生命周期钩子方法执行顺序
spring bean生命周期钩子方法一共有3种,执行顺序如下
- @PostConstruct 、@PreDestroy(javax.annotation)
- InitializingBean#afterPropertiesSet 、DisposableBean#destroy 回调接口
- 自定义 init() 、destroy() 方法
怎么去记这个顺序呢?这里以初始化来举例。
可以这样理解,越标准的越先执行,那么属于java规范的@PostConstruct
首先执行;而后spring接口InitializingBean#afterPropertiesSet
,最后才是自定义的方法。
销毁时同理,所以执行顺序依次是属于java规范的的@PreDestroy
、接口DisposableBean#destroy
、最后自定义destroy方法。
钩子方法执行时机
钩子方法在属性依赖注入完毕后执行,并且操作的raw bean reference,而不是proxy bean,这样可以使生命周期方法与proxy解耦。
自定义init、destory举例
- xml中定义
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
- @Bean注解中指定
- 如下
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
生命周期钩子方法的实现原理
看org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
,
先注入依赖属性,然后执行生命周期钩子方法。
//注入依赖属性,@AutoWired、@Resource
populateBean(beanName, mbd, instanceWrapper);
// 执行生命周期钩子方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
继续跟踪AbstractAutowireCapableBeanFactory#initializeBean
//通过CommonAnnotationBeanPostProcessor执行的@PostConstruct、@PreDestroy
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 执行InitializingBean、自定义钩子方法
invokeInitMethods(beanName, wrappedBean, mbd);
上边两行分别对应下边的两个标题 @PostConstruct的实现原理、 InitializingBean、自定义init方法实现原理。
@PostConstruct的实现原理
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization,执行了BeanPostProcessor#postProcessBeforeInitialization
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
是哪个BeanPostProcessor处理了@PostConstruct呢?CommonAnnotationBeanPostProcessor。
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
CommonAnnotationBeanPostProcessor是InitDestroyAnnotationBeanPostProcessor的子类,InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
metadata.invokeInitMethods(bean, beanName);
}
findLifecycleMetadata内部调了buildLifecycleMetadata,buildLifecycleMetadata里循环获取加了@PostConstruct、@PreDestory的方法,先获取当前类、再获取父类、再获取上一级父类直到Object,而且执行时机是先执行父类的方法、再执行子类的方法。
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
//这里确定了执行顺序,父类的初始化方法先执行
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}
初始化执行的原理很简单,就是反射执行初始化方法。
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleElement#invoke
public void invoke(Object target) throws Throwable {
ReflectionUtils.makeAccessible(this.method);
//反射执行初始化方法
this.method.invoke(target, (Object[]) null);
}
InitializingBean、自定义init方法实现原理
继续跟踪AbstractAutowireCapableBeanFactory#invokeInitMethods
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
//执行InitializingBean#afterPropertiesSet
((InitializingBean) bean).afterPropertiesSet();
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//执行自定义的init方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
自定义init方法是怎么执行的呢?AbstractAutowireCapableBeanFactory#invokeCustomInitMethod,拣重点看,也是反射执行方法
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
String initMethodName = mbd.getInitMethodName();
Assert.state(initMethodName != null, "No init method set");
Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);
//反射执行方法
methodToInvoke.invoke(bean);
}
总结
- @PostConstruct通过CommonAnnotationBeanPostProcessor#postProcessBeforeInitialization执行,postProcessBeforeInitialization在任何初始化方法(比如InitializingBean#afterPropertiesSet、自定义初始化方法)之前执行,所以@PostConstruct先执行,而后才是InitializingBean及自定义方法。
- InitializingBean#afterPropertiesSet、自定义init通过AbstractAutowireCapableBeanFactory#invokeInitMethods实现。
源代码: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
参考
以上是关于spring 声明周期钩子方法的主要内容,如果未能解决你的问题,请参考以下文章