前言
Spring框架之所以强大,其中有一个核心功能就是提供了扩展支持,Spring容器虽然管理了所有的Spring Bean,单例的bean初始化之后就会放入Spring容器,在整个生命周期内都不可变。但是在实际业务场景中,有时我们需要对bean有额外的扩展功能。
此时就可以用到Spring提供的众多扩展接口,本文就盘点下Spring框架中常用的扩展接口中的两个 InitializingBean和DisposableBean接口
一、InitializingBean 和 DisposableBean 接口
InitializingBean和DisposableBean都是一个接口,从名字可以看出分别是bean初始化和bean销毁相关的接口
InitialzingBean和DisposableBean源码分别如下:
1 public interface InitializingBean {
2
3 /**
4 * 初始化方法,在bean的属性设置完成后执行
5 */
6 void afterPropertiesSet() throws Exception;
7
8 }
1 public interface DisposableBean {
2
3 /**
4 * 销毁方法,在bean准备销毁的时候执行
5 */
6 void destroy() throws Exception;
7
8 }
这两个接口分别都只有一个方法需要实现,一个是初始化方法afterPropertiesSet()和销毁方法destroy()
如果bean实现了InitialzingBean接口,就需要实现afterPropertiesSet方法,当bean初始化完成就会自动调用该方法,做一些bean初始化之后的额外工作,另外除了该方法,配置bean的时候还可以配置bean的初始化方法,如配置init-method,这个同样是当bean初始化之后需要执行的初始化方法,而afterPropertiesSet方法是在init-method方法之前执行的。所以可以总结一个bean从创建到初始化完成的全部过程如下:
1、通过构造器创建bean
2、属性注入
3、执行afterPropertiesSet方法
4、执行init-method方法
使用案例如下:
1 public class MyBean implements InitializingBean{
2
3 private UserService userService;
4
5 public MyBean(){
6 System.out.println("执行构造器方法");
7 }
8
9 public void initMethod(){
10 System.out.println("执行配置的初始化方法");
11 }
12
13 @Override
14 public void afterPropertiesSet() throws Exception {
15 System.out.println("执行实现InitializingBean的初始化方法");
16 }
17
18 public UserService getUserService() {
19 return userService;
20 }
21
22 public void setUserService(UserService userService) {
23 System.out.println("属性注入时,执行该方法");
24 this.userService = userService;
25 }
26 }
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
5
6 <bean id="myBean" class="com.lucky.test.spring.demo.MyBean" init-method="initMethod">
7 <property name="userService" ref="userService"/>
8 </bean>
9
10 <bean id="userService" class="com.lucky.test.spring.demo.impl.UserServiceImpl"/>
11
12 </beans>
自定义MyBean实现了InitializingBean,并且配置了init-method和注入了一个属性UserService,则此bean加载的时候执行顺序应该是
1、执行构造器方法MyBean() -> 2.执行setUserSerivce方法属性注入 -> 3.执行afterPropertiesSet()方法 ->4.执行配置的初始化方法initMethod()
测试结果如下:
执行构造器方法
属性注入时,执行该方法
执行实现InitializingBean的初始化方法
执行配置的初始化方法
同理,实现了DisposableBean接口的方法需要实现destroy方法,同样执行顺序也是在配置的销毁方法destroy-method前面执行,所以当bean销毁时的执行顺序为
1、执行DisposableBean接口的destroy()方法
2、执行配置的destroy-method的方法
使用案例如下:
1 public class MyBean implements InitializingBean, DisposableBean{
2
3 @Override
4 public void destroy() throws Exception {
5 System.out.println("执行实现了DisposableBean接口的destroy方法");
6 }
7
8 public void destroyMethod(){
9 System.out.println("执行配置的销毁方法destroyMethod");
10 }
11
12 private UserService userService;
13
14 public MyBean(){
15 System.out.println("执行构造器方法");
16 }
17
18 public void initMethod(){
19 System.out.println("执行配置的初始化方法");
20 }
21
22 @Override
23 public void afterPropertiesSet() throws Exception {
24 System.out.println("执行实现InitializingBean的初始化方法");
25 }
26
27 public UserService getUserService() {
28 return userService;
29 }
30
31 public void setUserService(UserService userService) {
32 System.out.println("属性注入时,执行该方法");
33 this.userService = userService;
34 }
35 }
1 <bean id="myBean" class="com.lucky.test.spring.demo.MyBean" init-method="initMethod" destroy-method="destroyMethod">
2 <property name="userService" ref="userService"/>
3 </bean>
将MyBean实现了DisposableBean接口,实现了destroy方法,则销毁该bean的时候会先执行destroy方法,再执行配置的destroyMethod方法,测试结果如下:
1 执行实现了DisposableBean接口的destroy方法
2 执行配置的销毁方法destroyMethod
二、InitializingBean和DisposableBean接口的实现原理
目前我们可以了解到实现了InitializingBean和DisposableBean接口的bean,会在bean初始化和销毁的时候分别执行这两个方法,那么具体是如何执行的呢?不妨从源码来分析看看。
首先看初始化方法是如何执行的,从Spring容器中获取bean需要执行调用BeanFactory的getBean方法,如果不存在就进行初始化,在初始化的过程中,核心步骤是执行了doCreateBean方法
该方法核心流程主要有三步,分别如下:
1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
2 throws BeanCreationException {
3 //...
4 /** 1.通过构造器创建bean*/
5 createBeanInstance(beanName, mbd, args);
6 /** 2.bean属性填充(依赖注入其他的bean)*/
7 populateBean(beanName, mbd, instanceWrapper);
8 /** 3.执行bean的初始化方法*/
9 exposedObject = initializeBean(beanName, exposedObject, mbd);
10 //...
11 return exposedObject;
12 }
其中执行bean初始化的方法就是initializeBean方法,源码如下:
1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
2 if (System.getSecurityManager() != null) {
3 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
4 invokeAwareMethods(beanName, bean);
5 return null;
6 }, getAccessControlContext());
7 }
8 else {
9 invokeAwareMethods(beanName, bean);
10 }
11
12 Object wrappedBean = bean;
13 if (mbd == null || !mbd.isSynthetic()) {
14 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
15 }
16
17 try {
18 /** 执行初始化方法具体逻辑*/
19 invokeInitMethods(beanName, wrappedBean, mbd);
20 }
21 catch (Throwable ex) {
22 throw new BeanCreationException(
23 (mbd != null ? mbd.getResourceDescription() : null),
24 beanName, "Invocation of init method failed", ex);
25 }
26 if (mbd == null || !mbd.isSynthetic()) {
27 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
28 }
29
30 return wrappedBean;
31 }
此处最终又调用了 invokeInitMethods方法来执行初始化方法,源码如下:
1 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
2 throws Throwable {
3
4 /** 1.判断当前bean是否是 InitializingBean的实现类 */
5 boolean isInitializingBean = (bean instanceof InitializingBean);
6 if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
7
8 if (System.getSecurityManager() != null) {
9 try {
10 /** 2.将bean转化成InitializingBean类型,直接调用afterPropertiesSet方法*/
11 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
12 ((InitializingBean) bean).afterPropertiesSet();
13 return null;
14 }, getAccessControlContext());
15 }
16 catch (PrivilegedActionException pae) {
17 throw pae.getException();
18 }
19 }
20 else {
21 /** 2.将bean转化成InitializingBean类型,直接调用afterPropertiesSet方法*/
22 ((InitializingBean) bean).afterPropertiesSet();
23 }
24 }
25
26 if (mbd != null && bean.getClass() != NullBean.class) {
27 /** 3.获取bean定义的init-method方法*/
28 String initMethodName = mbd.getInitMethodName();
29 /** 4.判断init-method方法是否存在,且方法名不是afterPropertiesSet方法(因为afterPropertiesSet方法已经执行过了)*/
30 if (StringUtils.hasLength(initMethodName) &&
31 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
32 !mbd.isExternallyManagedInitMethod(initMethodName)) {
33 /** 5.通过反射调用init-method*/
34 invokeCustomInitMethod(beanName, bean, mbd);
35 }
36 }
37 }
从源码可以看出,在invokeInitMethods方法中,会先判断当前bean是否实现了InitializingBean接口,如果实现了该接口,则直接将该bean转化为InitializingBean类型,然后直接执行afterPropertiiesSet方法;然后再判断bean是否配置了init-method,
如果配置了init-method且方法名有效,则通过反射来执行init-method方法。另外这两个初始化方法是在同一个函数中执行的,所以说如果afterPropertiesSet方法执行报错了,那么init-method方法就不会再执行了。
再看下bean的销毁过程,当Spring容器销毁时,会将容器中的所有单例bean先全部销毁,在ApplicationContext中的destroyBeans()方法就是用来处理销毁bean的任务的,源码如下:
1 protected void destroyBeans() {
2 /** 调用destroySingletons()方法*/
3 getBeanFactory().destroySingletons();
4 } 1 public void destroySingleton(String beanName) {
2 //将bean从三级缓存中删除
3 removeSingleton(beanName);
4
5 //从disposableBeans中获取该bean的DisposableBean对象
6 DisposableBean disposableBean;
7 synchronized (this.disposableBeans) {
8 disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
9 }
//执行destroyBean方法
10 destroyBean(beanName, disposableBean);
11 }
1 protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
2 // Trigger destruction of dependent beans first...
3 Set<String> dependencies;
4 synchronized (this.dependentBeanMap) {
5 // Within full synchronization in order to guarantee a disconnected Set
6 dependencies = this.dependentBeanMap.remove(beanName);
7 }
8 if (dependencies != null) {
9 if (logger.isTraceEnabled()) {
10 logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
11 }
12 for (String dependentBeanName : dependencies) {
13 destroySingleton(dependentBeanName);
14 }
15 }
16
17 // 执行DisposableBean的destroy方法,因为前面将每个bean都转化成了DisposableBean对象,所以每个对象都会执行destroy方法
18 if (bean != null) {
19 try {
20 bean.destroy();
21 }
22 catch (Throwable ex) {
23 if (logger.isWarnEnabled()) {
24 logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
25 }
26 }
27 }
28
29 // Trigger destruction of contained beans...
30 Set<String> containedBeans;
31 synchronized (this.containedBeanMap) {
32 // Within full synchronization in order to guarantee a disconnected Set
33 containedBeans = this.containedBeanMap.remove(beanName);
34 }
35 if (containedBeans != null) {
36 for (String containedBeanName : containedBeans) {
37 destroySingleton(containedBeanName);
38 }
39 }
40
41 // Remove destroyed bean from other beans' dependencies.
42 synchronized (this.dependentBeanMap) {
43 for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
44 Map.Entry<String, Set<String>> entry = it.next();
45 Set<String> dependenciesToClean = entry.getValue();
46 dependenciesToClean.remove(beanName);
47 if (dependenciesToClean.isEmpty()) {
48 it.remove();
49 }
50 }
51 }
52
53 // Remove destroyed bean's prepared dependency information.
54 this.dependenciesForBeanMap.remove(beanName);
55 }
调用bean的封装类DisposableBeanAdapter的destroy方法,源码如下:
1 public void destroy() {
2 if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
3 for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
4 processor.postProcessBeforeDestruction(this.bean, this.beanName);
5 }
6 }
7
8 if (this.invokeDisposableBean) {
9 if (logger.isTraceEnabled()) {
10 logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
11 }
12 try {
13 if (System.getSecurityManager() != null) {
14 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
15 ((DisposableBean) this.bean).destroy();
16 return null;
17 }, this.acc);
18 }
19 else {
20 ((DisposableBean) this.bean).destroy();
21 }
22 }
23 catch (Throwable ex) {
24 String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
25 if (logger.isDebugEnabled()) {
26 logger.warn(msg, ex);
27 }
28 else {
29 logger.warn(msg + ": " + ex);
30 }
31 }
32 }
33
34 if (this.destroyMethod != null) {
35 invokeCustomDestroyMethod(this.destroyMethod);
36 }
37 else if (this.destroyMethodName != null) {
38 Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
39 if (methodToInvoke != null) {
40 invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
41 }
42 }
43 }
可以看出销毁的逻辑和初始化的逻辑基本是一致,先从DisposableBeanAdapter对象中获取当前bean对象转化成DisposableBean对象,然后直接调用destroy()方法;然后再通过反射调用bean配置的destroyMethod方法。
在容器中有个集合会保存所有需要销毁的bean的集合,也就是上面第二块代码中的Map<String, Object>disposableBeans,当每个bean初始化之后,也就是doCreateBean方法中,当执行完全部初始化方法之后,会执行一个registerDisposableBeanIfNecessary方法,该方法的作用是将当前bean封装成一个销毁对象DisposabelBean的实现类DisposableBeanAdapter,然后加入到disposableBeans中,所以当容器需要销毁时,会遍历这个集合依次调用DisposableBeanAdapter对象的destroy方法。
总结:
1、InitializingBean和DisposableBean接口的方法分别在bean初始化和bean销毁的时候执行
2、InitializingBean和DisposableBean接口的方法执行顺序是在bean自定义的初始化方法init-method和destroy-method之前执行
3、InitializingBean和DisposableBean接口的方法是将bean强制转换成该接口类型,直接调用对应的方法;而init-method和destroy-method方法的调用是通过反射来执行
4、通过接口的方式效率更高,但是和Spring框架API耦合,需要实现Spring提供的接口;自定义方法方式使用反射效率低,但是不需要依赖Spring的API
5、两种初始化方法是在同一个线程中同一个方法中执行的,所以先执行的接口方法如果报错,那么自定义配置的方法则不会再执行