前言
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、两种初始化方法是在同一个线程中同一个方法中执行的,所以先执行的接口方法如果报错,那么自定义配置的方法则不会再执行