Spring的refresh方法-优雅初始化_销毁Bean方式番外篇(6

所有的内容都是基于 https://gitee.com/chris_777/spring-boot2.1.3 springboot 源码
main函数入口org.springframework.boot.tests.hibernate52.Hibernate52Application.main

Spring为我们提供了许多接口,方便我们嵌入自己的业务逻辑。今天记录一下,Spring如何优雅的对Bean进行初始化或者销毁。


  • @PostConstruct/@PreDestroy注解
  • init-method/destroy-method
  • InitializingBean/DisposableBean
  • ContextRefreshedEvent/ContextClosedEvent
  • LifecycleProcessor

咱们先看一下,Spring是如何去管理Bean的初始化以及销毁的。由于Bean的初始化源码比较分散,而销毁的源码是在一起的,我们先看一下Spring如何销毁的源码(只针对destroy方法)。


  1. Spring是如何管理Bean的销毁的

doCreateBean方法里面的 registerDisposableBeanIfNecessary 方法,此时该Bean已经初始化完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
//判断改Bean是否为 Disposable Bean
//里面的逻辑是
//1.判断是否有destroy方法
//2.属于DisposableBean类型 或 AutoCloseable类型
//4.DestructionAwareBeanPostProcessorBean处理器
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
//单例
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
//创建 DisposableBeanAdapter适配器,将bean保存到disposableBeans集合中
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
//注册回调
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
  1. 如何销毁

初始化的时候,由于传入的是一个DisposableBeanAdapter对象,所以调用的也是该对象的DisposableBeanAdapter的destroy方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
//获取自己的(根据接口中的一个方法返回true或false判断)BeanPostProcessors执行器,调用postProcessBeforeDestruction方法
//这里就会执行 @PreDestroy 注解的逻辑
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
//调用destroy方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
((DisposableBean) this.bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.info(msg, ex);
}
else {
logger.info(msg + ": " + ex);
}
}
}
//调用改Bean的destroy方法
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToCall = determineDestroyMethod(this.destroyMethodName);
if (methodToCall != null) {
invokeCustomDestroyMethod(methodToCall);
}
}
}
  1. @PostConstruct/@PreDestroy注解

CommonAnnotationBeanPostProcessor类(InitDestroyAnnotationBeanPostProcessor类的子类),在初始化时会初始化这两个注解。

1
2
3
4
5
6
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}

解析注解的逻辑在InitDestroyAnnotationBeanPostProcessor父类中,与 Spring的refresh方法-BeanPostProcessor番外篇(2 中@Autowired注解处理方式一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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);
}

@PostConstruct标注的方法,会在执行初始化方法的时候调用Bean处理器时触发。
@PreDestroy注解,已经在文章开始统一说明。

  1. init-method/destroy-method

在Bean进行初始化的时候,会调用Bean的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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
//获取bean的init方法
String initMethodName = mbd.getInitMethodName();
Assert.state(initMethodName != null, "No init method set");
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));

//.......省略代码
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
}
//调用init方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(initMethod);
return null;
});
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
initMethod.invoke(bean), getAccessControlContext());
}
catch (PrivilegedActionException pae) {
InvocationTargetException ex = (InvocationTargetException) pae.getException();
throw ex.getTargetException();
}
}
else {
try {
ReflectionUtils.makeAccessible(initMethod);
initMethod.invoke(bean);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}

destroy-method,已经在文章开始统一说明。

  1. InitializingBean/DisposableBean

InitializingBean实现方式,请参考 Spring的refresh方法-InitializingBean番外篇(4
DisposableBean文章,已经在文章开始统一说明。

  1. ContextRefreshedEvent/ContextClosedEvent

Spring会在每个相应阶段结束之后,发布对应的事件。ContextRefreshedEvent事件会在所有非懒加载对象初始化完成之后触发的事件。
参考 Spring的refresh方法-ApplicationListener番外篇(4
org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)


发布刷新完成事件
publishEvent(new ContextRefreshedEvent(this));


代码位置
org.springframework.context.support.AbstractApplicationContext#finishRefresh


发布关闭事件
publishEvent(new ContextClosedEvent(this))


代码位置
org.springframework.context.support.AbstractApplicationContext#doClose


  1. LifecycleProcessor

Spring会在结束刷新的时候,注册一个Bean的名字为lifecycleProcessor的对象,我们可以依靠改对象,来完成我们初始化或者销毁对象的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface LifecycleProcessor extends Lifecycle {

/**
* 刷新完成触发
*/
void onRefresh();

/**
* 关闭时触发
*/
void onClose();

}

我们来实践一下,正常情况下,会依次输出:
onLifecycleProcessorRefresh>>>>>>>
onLifecycleProcessorClose>>>>>>>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@Component("lifecycleProcessor")
public class MyLifecycleProcessorTest implements LifecycleProcessor,ApplicationContextAware {

private ApplicationContext applicationContext;

@Override
public void onRefresh() {
ManualRegisterBean manualRegisterBean = (ManualRegisterBean) applicationContext.getBean(ManualRegisterBean.class.getName());
manualRegisterBean.onLifecycleProcessorRefresh();
}

@Override
public void onClose() {
ManualRegisterBean manualRegisterBean = (ManualRegisterBean) applicationContext.getBean(ManualRegisterBean.class.getName());
manualRegisterBean.onLifecycleProcessorClose();
}

@Override
public void start() {

}

@Override
public void stop() {

}

@Override
public boolean isRunning() {
return false;
}

/**
* org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
* 会在执行初始化方法的时候,通过Bean处理器进行注入
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
}


@Chris
public class ManualRegisterBean {


public void onContextRefreshedEvent() {
System.out.println("ContextRefreshedEvent>>>>>>>");
}

public void onAfterSingletonsInstantiated() {
System.out.println("afterSingletonsInstantiated>>>>>>>");
}

public void onLifecycleProcessorRefresh() {
System.out.println("onLifecycleProcessorRefresh>>>>>>>");
}

public void onLifecycleProcessorClose() {
System.out.println("onLifecycleProcessorClose>>>>>>>");
}

}
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信