• spring扩展接口解析1--InitializingBean接口和Disposable接口


    前言

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

  • 相关阅读:
    ViewState
    jar包签名
    Eclipse打JAR包引用的第三方JAR包找不到 问题解决
    java项目打jar包
    像VS一样在Eclipse中使用(拖拉)控件
    Myeclipse buildpath 加server library
    nativeswing的关闭问题 当出现Socket连接未断开错误
    Windows 7 配置jdk 1.7环境变量
    myeclipse添加server library
    RichFaces 大概
  • 原文地址:https://www.cnblogs.com/jackion5/p/13274098.html
Copyright © 2020-2023  润新知