• 【Spring】配置initMethod 与 配置destroyMethod 的实现原理(七)


      关于在Spring 容器 初始化和销毁 bean 前所做的操作有三种方式定义:

    • 第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化后和销毁bean之前进行的操作

    • 第二种:通过bean实现InitializingBean和 DisposableBean接口

    • 第三种:通过 在xml中配置init-method 和 destory-method方法,或者 配置@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod") 注解

      执行顺序:@PostConstruct -> InitializingBean -> 配置initMethod -> @PreDestroy -> DisposableBean -> 配置destroyMethod

      本章介绍第一种

      第一种见:【Spring】@PostConstruct 与 @PreDestroy 的实现原理(五)

      第二种见:【Spring】InitializingBean与 DisposableBean 接口的实现原理(六)

    一、配置initMethod 与 配置destroyMethod 方法

    1、BeanPerson类

     1 public class BeanPerson {
     2 
     3     public void say(String word) {
     4         System.out.println("Hello, " + word);
     5     }
     6 
     7     public BeanPerson() {
     8         System.out.println("BeanPerson() ");
     9     }
    10 
    11     public void initMethod(){
    12         System.out.println("initMethod()....");
    13     }
    14 
    15     public void destroyMethod(){
    16         System.out.println("destroyMethod()....");
    17     }
    18 }

    2、xml配置

    <bean id="person" class="com.test.ioc.BeanPerson" init-method="initMethod" destroy-method="destroyMethod"></bean>   

    3、@Bean注解配置

    @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")

    二、原理图

      

    三、配置initMethod 方法实现原理

    1、实例化bean时,createBeat()->doCreateBeat()->initializeBean()

      初始化 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     } else {
     8         // 若bean实现了XXXAware接口进行方法的回调
     9         invokeAwareMethods(beanName, bean);
    10     }
    11 
    12     Object wrappedBean = bean;
    13     if (mbd == null || !mbd.isSynthetic()) {
    14         // 支持初始化前bean的后置处理器
    15         wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    16     }
    17 
    18     try {
    19         // 调用初始化方法
    20         invokeInitMethods(beanName, wrappedBean, mbd);
    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 }

    2、其中调用了初始化方法 invokeInitMethods() ,如下:

     1 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
     2             throws Throwable {
     3     // 判断容器中是否实现了InitializingBean接口
     4     boolean isInitializingBean = (bean instanceof InitializingBean);
     5     if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
     6         if (logger.isTraceEnabled()) {
     7             logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
     8         }
     9         if (System.getSecurityManager() != null) {
    10             try {
    11                 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    12                     ((InitializingBean) bean).afterPropertiesSet();
    13                     return null;
    14                 }, getAccessControlContext());
    15             } catch (PrivilegedActionException pae) {
    16                 throw pae.getException();
    17             }
    18         } else {
    19             // 回调实现InitializingBean接口的afterPropertiesSet()方法
    20             ((InitializingBean) bean).afterPropertiesSet();
    21         }
    22     }
    23 
    24     if (mbd != null && bean.getClass() != NullBean.class) {
    25         // bean定义中看是否有配置的init方法
    26         String initMethodName = mbd.getInitMethodName();
    27         // 判断自定义的init方法名称不叫afterPropertiesSet
    28         if (StringUtils.hasLength(initMethodName) &&
    29                 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
    30                 !mbd.isExternallyManagedInitMethod(initMethodName)) {
    31             // 调用配置的初始化方法
    32             invokeCustomInitMethod(beanName, bean, mbd);
    33         }
    34     }
    35 }

    3、invokeCustomInitMethod() 调用配置的初始化方法

     1 protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
     2         throws Throwable {
     3 
     4     // 从bean定义中获取初始化方法名称
     5     String initMethodName = mbd.getInitMethodName();
     6     Assert.state(initMethodName != null, "No init method set");
     7     // 获得初始化方法
     8     Method initMethod = (mbd.isNonPublicAccessAllowed() ?
     9             BeanUtils.findMethod(bean.getClass(), initMethodName) :
    10             ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
    11 
    12     if (initMethod == null) {
    13         if (mbd.isEnforceInitMethod()) {
    14             throw new BeanDefinitionValidationException("Could not find an init method named '" +
    15                     initMethodName + "' on bean with name '" + beanName + "'");
    16         } else {
    17             if (logger.isTraceEnabled()) {
    18                 logger.trace("No default init method named '" + initMethodName +
    19                         "' found on bean with name '" + beanName + "'");
    20             }
    21             // Ignore non-existent default lifecycle methods.
    22             return;
    23         }
    24     }
    25 
    26     if (logger.isTraceEnabled()) {
    27         logger.trace("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
    28     }
    29     Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);
    30 
    31     if (System.getSecurityManager() != null) {
    32         AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    33             ReflectionUtils.makeAccessible(methodToInvoke);
    34             return null;
    35         });
    36         try {
    37             AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
    38                     methodToInvoke.invoke(bean), getAccessControlContext());
    39         } catch (PrivilegedActionException pae) {
    40             InvocationTargetException ex = (InvocationTargetException) pae.getException();
    41             throw ex.getTargetException();
    42         }
    43     } else {
    44         try {
    45             ReflectionUtils.makeAccessible(methodToInvoke);
    46             // 调用对象的初始化方法
    47             methodToInvoke.invoke(bean);
    48         } catch (InvocationTargetException ex) {
    49             throw ex.getTargetException();
    50         }
    51     }
    52 }

      注:bean定义的初始化方法名称,是在Spring解析的时候,通过判断注解或xml配置的到的,同时解析也会把销毁方法名称,放到bean定义中

    四、配置destroyMethod 方法实现原理

     1、在容器关闭时,调用方法链:context.clonse() -> doClose() -> destroyBeans() -> destroySingletons() ->destroySingleton()

      销毁单例方法 destroySingleton() 如下:

     1 public void destroySingleton(String beanName) {
     2     // Remove a registered singleton of the given name, if any.
     3     // 移除缓存
     4     removeSingleton(beanName);
     5 
     6     // Destroy the corresponding DisposableBean instance.
     7     DisposableBean disposableBean;
     8     // 加锁
     9     synchronized (this.disposableBeans) {
    10         // 根据名称,从需要销毁的是实例集合移除实例,得到disposableBean
    11         disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
    12     }
    13     // 销毁bean
    14     destroyBean(beanName, disposableBean);
    15 }

    2、销毁时,从disposableBeans 获取对象(对象是在bean创建的时候,放入的,具体见上一篇)

     1 protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
     2         // Trigger destruction of dependent beans first...
     3         Set<String> dependencies;
     4         // 移除依赖
     5         synchronized (this.dependentBeanMap) {
     6             // Within full synchronization in order to guarantee a disconnected Set
     7             dependencies = this.dependentBeanMap.remove(beanName);
     8         }
     9         if (dependencies != null) {
    10             if (logger.isTraceEnabled()) {
    11                 logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
    12             }
    13             for (String dependentBeanName : dependencies) {
    14                 destroySingleton(dependentBeanName);
    15             }
    16         }
    17 
    18         // Actually destroy the bean now...
    19         // 现在真正销毁
    20         if (bean != null) {
    21             try {
    22                 // 调用销毁方法
    23                 bean.destroy();
    24             }
    25             catch (Throwable ex) {
    26                 if (logger.isWarnEnabled()) {
    27                     logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
    28                 }
    29             }
    30         }
    31 
    32         // Trigger destruction of contained beans...
    33         Set<String> containedBeans;
    34         synchronized (this.containedBeanMap) {
    35             // Within full synchronization in order to guarantee a disconnected Set
    36             containedBeans = this.containedBeanMap.remove(beanName);
    37         }
    38         if (containedBeans != null) {
    39             for (String containedBeanName : containedBeans) {
    40                 destroySingleton(containedBeanName);
    41             }
    42         }
    43 
    44         // Remove destroyed bean from other beans' dependencies.
    45         synchronized (this.dependentBeanMap) {
    46             for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
    47                 Map.Entry<String, Set<String>> entry = it.next();
    48                 Set<String> dependenciesToClean = entry.getValue();
    49                 dependenciesToClean.remove(beanName);
    50                 if (dependenciesToClean.isEmpty()) {
    51                     it.remove();
    52                 }
    53             }
    54         }
    55 
    56         // Remove destroyed bean's prepared dependency information.
    57         // 移除依赖关系集中对象
    58         this.dependenciesForBeanMap.remove(beanName);
    59     }

    3、bean.destroy() 方法, 这里的bean对象是 DisposableBeanAdapter对象 如下:

     1 // 销毁
     2 @Override
     3 public void destroy() {
     4     if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
     5         for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
     6             // 调持销毁前bean的后置处理器
     7             processor.postProcessBeforeDestruction(this.bean, this.beanName);
     8         }
     9     }
    10 
    11     // 判断是否实现DisposableBean接口
    12     if (this.invokeDisposableBean) {
    13         if (logger.isTraceEnabled()) {
    14             logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
    15         }
    16         try {
    17             if (System.getSecurityManager() != null) {
    18                 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    19                     ((DisposableBean) this.bean).destroy();
    20                     return null;
    21                 }, this.acc);
    22             }
    23             else {
    24                 // 强转,调用destroy()方法
    25                 ((DisposableBean) this.bean).destroy();
    26             }
    27         }
    28         catch (Throwable ex) {
    29             String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
    30             if (logger.isDebugEnabled()) {
    31                 logger.warn(msg, ex);
    32             }
    33             else {
    34                 logger.warn(msg + ": " + ex);
    35             }
    36         }
    37     }
    38 
    39     if (this.destroyMethod != null) {
    40         // 调用配置的销毁方法
    41         invokeCustomDestroyMethod(this.destroyMethod);
    42     }
    43     else if (this.destroyMethodName != null) {
    44         Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
    45         if (methodToInvoke != null) {
    46             // 调用配置的销毁方法
    47             invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
    48         }
    49     }
    50 }

    4、其中invokeCustomDestroyMethod() 方法,调用了对象的销毁方法

     1 private void invokeCustomDestroyMethod(final Method destroyMethod) {
     2     // 销毁方法参数数量
     3     int paramCount = destroyMethod.getParameterCount();
     4     final Object[] args = new Object[paramCount];
     5     if (paramCount == 1) {
     6         args[0] = Boolean.TRUE;
     7     }
     8     if (logger.isTraceEnabled()) {
     9         logger.trace("Invoking destroy method '" + this.destroyMethodName +
    10                 "' on bean with name '" + this.beanName + "'");
    11     }
    12     try {
    13         if (System.getSecurityManager() != null) {
    14             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    15                 ReflectionUtils.makeAccessible(destroyMethod);
    16                 return null;
    17             });
    18             try {
    19                 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
    20                     destroyMethod.invoke(this.bean, args), this.acc);
    21             }
    22             catch (PrivilegedActionException pax) {
    23                 throw (InvocationTargetException) pax.getException();
    24             }
    25         }
    26         else {
    27             ReflectionUtils.makeAccessible(destroyMethod);
    28             // 调用对象的销毁方法
    29             destroyMethod.invoke(this.bean, args);
    30         }
    31     }
    32     catch (InvocationTargetException ex) {
    33         String msg = "Destroy method '" + this.destroyMethodName + "' on bean with name '" +
    34                 this.beanName + "' threw an exception";
    35         if (logger.isDebugEnabled()) {
    36             logger.warn(msg, ex.getTargetException());
    37         }
    38         else {
    39             logger.warn(msg + ": " + ex.getTargetException());
    40         }
    41     }
    42     catch (Throwable ex) {
    43         logger.warn("Failed to invoke destroy method '" + this.destroyMethodName +
    44                 "' on bean with name '" + this.beanName + "'", ex);
    45     }
    46 }
  • 相关阅读:
    POJ2155 Matrix 【二维线段树】
    BZOJ4785 [Zjoi2017]树状数组 【二维线段树 + 标记永久化】
    B1027 打印沙漏
    Tomcat无法成功启动——双击startup.bat闪退
    MySQL在cmd命令行查看端口号
    1009 说反话(类似回文字符串)
    除基取余法,
    日期差值
    怎么把VS里的scanf_s换成scanf
    联想小新潮怎么修改fn热键以及怎么进入bios状态
  • 原文地址:https://www.cnblogs.com/h--d/p/14656073.html
Copyright © 2020-2023  润新知