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

  • 相关阅读:
    动态生成 Excel 文件供浏览器下载的注意事项
    JavaEE 中无用技术之 JNDI
    CSDN 泄露用户密码给我们什么启示
    刚发布新的 web 单点登录系统,欢迎下载试用,欢迎提建议
    jQuery jqgrid 对含特殊字符 json 数据的 Java 处理方法
    一个 SQL 同时验证帐号是否存在、密码是否正确
    PostgreSQL 数据库在 Windows Server 2008 上安装注意事项
    快速点评 Spring Struts Hibernate
    Apache NIO 框架 Mina 使用中出现 too many open files 问题的解决办法
    解决 jQuery 版本升级过程中出现 toLowerCase 错误 更改 doctype
  • 原文地址:https://www.cnblogs.com/jackion5/p/13274098.html
Copyright © 2011-2022 走看看