zoukankan      html  css  js  c++  java
  • 【Spring】@PostConstruct 与 @PreDestroy 的实现原理(五)

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

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

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

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

      本章介绍第一种

    一、@PostConstruct 和 @PreDestroy 使用

     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         // 初始化方法
    12     @PostConstruct
    13     public void postConstruct(){
    14         System.out.println("postConstruct()....");
    15     }
    16 
    17         // 销毁方法
    18     @PreDestroy
    19     public void preDestroy(){
    20         System.out.println("preDestroy().....");
    21     }
    22 
    23 }

       在对应的方法上加上@PostConstruct 和 @PreDestroy 注解即可

    二、原理图

      实现是通过Bean后置处理器来实现的

      

    三、@PostConstruct 实现原理

    1、在初始化bean的时候,会调用doCreateBean(),方法中代码,支持合并Bean定义后置处理器,由于Spring内置类CommonAnnotationBeanPostProcessor后置处理器,所以调用了CommonAnnotationBeanPostProcessor后置处理器,进行合并Bean定义后置处理

    2、调用CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()方法 

     1 // 后置处理合并Bean定义
     2 @Override
     3 public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
     4     // 后置处理合并Bean定义
     5     // 主要是:查找或构建一个生命周期元数据对象,父类postProcessMergedBeanDefinition()方法调用了findLifecycleMetadata()
     6     super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
     7     // 查找或构建一个资源元数据对象(注入信息元数据对象)
     8     InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
     9     metadata.checkConfigMembers(beanDefinition);
    10 } 

     3、CommonAnnotationBeanPostProcessor父类InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()

    1 // 后置处理合并Bean定义
    2 @Override
    3 public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    4     // 查找或构建一个生命周期元数据对象
    5     LifecycleMetadata metadata = findLifecycleMetadata(beanType);
    6     metadata.checkConfigMembers(beanDefinition);
    7 }

    4、CommonAnnotationBeanPostProcessor父类InitDestroyAnnotationBeanPostProcessor的findLifecycleMetadata()方法,查找bean的生命周期元数据对象,没有的话,调用buildLifecycleMetadata(),构建了一个LifecycleMetadata对象(生命周期元数据对象)

     1 /**
     2  * 查找bean的生命周期元数据对象,没有的话,调用buildLifecycleMetadata(),构建了一个
     3  * @param clazz
     4  * @return
     5  */
     6 private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
     7     if (this.lifecycleMetadataCache == null) {
     8         // Happens after deserialization, during destruction...
     9         return buildLifecycleMetadata(clazz);
    10     }
    11     // Quick check on the concurrent map first, with minimal locking.
    12     LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
    13     if (metadata == null) {
    14         synchronized (this.lifecycleMetadataCache) {
    15             // 根据clazz,构建了一个bean的生命周期元数据对象
    16             metadata = this.lifecycleMetadataCache.get(clazz);
    17             if (metadata == null) {
    18                 metadata = buildLifecycleMetadata(clazz);
    19                 this.lifecycleMetadataCache.put(clazz, metadata);
    20             }
    21             return metadata;
    22         }
    23     }
    24     return metadata;
    25 }

    5、调用buildLifecycleMetadata(),构建了一个

     1 /**
     2  * 构建了一个bean的生命周期元数据对象
     3  * 即获得了一个Bean的 初始化方法集合 和 销毁方法集合
     4  * @param clazz
     5  * @return
     6  */
     7 private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
     8     if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
     9         return this.emptyLifecycleMetadata;
    10     }
    11 
    12     // 初始化方法集合
    13     List<LifecycleElement> initMethods = new ArrayList<>();
    14     // 销毁方法集合
    15     List<LifecycleElement> destroyMethods = new ArrayList<>();
    16     Class<?> targetClass = clazz;
    17 
    18     do {
    19 
    20         final List<LifecycleElement> currInitMethods = new ArrayList<>();
    21 
    22         final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
    23 
    24         // 利用反射获取对象方法,进行处理
    25         ReflectionUtils.doWithLocalMethods(targetClass, method -> {
    26             // 是否是@PostConstruct注解
    27             // initAnnotationType这个值在 CommonAnnotationBeanPostProcessor()构造方法中设置
    28             if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
    29                 LifecycleElement element = new LifecycleElement(method);
    30                 currInitMethods.add(element);
    31                 if (logger.isTraceEnabled()) {
    32                     logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
    33                 }
    34             }
    35 
    36             // 是否是@PreDestroy
    37             if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
    38                 currDestroyMethods.add(new LifecycleElement(method));
    39                 if (logger.isTraceEnabled()) {
    40                     logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
    41                 }
    42             }
    43         });
    44         // 初始化方法集合
    45         initMethods.addAll(0, currInitMethods);
    46         // 销毁方法集合
    47         destroyMethods.addAll(currDestroyMethods);
    48         targetClass = targetClass.getSuperclass();
    49     }
    50     while (targetClass != null && targetClass != Object.class);
    51 
    52     return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
    53             new LifecycleMetadata(clazz, initMethods, destroyMethods));
    54 }

    6、创建CommonAnnotationBeanPostProcessor,通用Bean后置处理器的时候,设置了初始化注解、销毁注解

    1 // CommonAnnotationBeanPostProcessor()构造方法,
    2 // 初始化了2个值@PostConstruct,@PreDestroy
    3 public CommonAnnotationBeanPostProcessor() {
    4     setOrder(Ordered.LOWEST_PRECEDENCE - 3);
    5     setInitAnnotationType(PostConstruct.class);
    6     setDestroyAnnotationType(PreDestroy.class);
    7     ignoreResourceType("javax.xml.ws.WebServiceContext");
    8 }

    7、doCreateBean(),方法中,支持初始化前bean的后置处理器

      调用了CommonAnnotationBeanPostProcessor后置处理器,进行初始化前后置处理

    8、调用CommonAnnotationBeanPostProcessor#postProcessBeforeInitialization()方法

     1 @Override
     2 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
     3     // 查找或构建一个生命周期元数据对象(同上)
     4     LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
     5     try {
     6         // 调用初始化方法
     7         metadata.invokeInitMethods(bean, beanName);
     8     }
     9     catch (InvocationTargetException ex) {
    10         throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    11     }
    12     catch (Throwable ex) {
    13         throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    14     }
    15     return bean;
    16 }

    9、调用初始化方法

     1 // 调用初始化方法
     2 public void invokeInitMethods(Object target, String beanName) throws Throwable {
     3     // 获取后置处理器检查过的初始化方法集合
     4     Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
     5     Collection<LifecycleElement> initMethodsToIterate =
     6             (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
     7     if (!initMethodsToIterate.isEmpty()) {
     8         // 遍历
     9         for (LifecycleElement element : initMethodsToIterate) {
    10             if (logger.isTraceEnabled()) {
    11                 logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
    12             }
    13             // 调用对应的初始化方法
    14             element.invoke(target);
    15         }
    16     }
    17 }

    四、@PreDestroy 实现原理

      和@PostConstruct原理一样只是最后出触发条件不一样,当调用容器close()方法销毁时,会调用doClose(),然后destroy()

    7、destroy(),方法中,支持销毁前bean的后置处理器,调用了CommonAnnotationBeanPostProcessor后置处理器,进行销毁前后置处理

    1 @Override
    2 public void destroy() {
    3     if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
    4         for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
    5             // 进行销毁前后置处理
    6             processor.postProcessBeforeDestruction(this.bean, this.beanName);
    7         }
    8     }
    9 }

    8、调调用CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction()方法

     1 // 用销毁前bean的后置处理器方法
     2 @Override
     3 public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
     4     // 查找或构建一个生命周期元数据对象
     5     LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
     6     try {
     7         // 调用销毁方法
     8         metadata.invokeDestroyMethods(bean, beanName);
     9     }
    10     catch (InvocationTargetException ex) {
    11         String msg = "Destroy method on bean with name '" + beanName + "' threw an exception";
    12         if (logger.isDebugEnabled()) {
    13             logger.warn(msg, ex.getTargetException());
    14         }
    15         else {
    16             logger.warn(msg + ": " + ex.getTargetException());
    17         }
    18     }
    19     catch (Throwable ex) {
    20         logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
    21     }
    22 }

    9、调用销毁方法

     1 public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
     2     // 获取后置处理器检查过的销毁方法集合
     3     Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods;
     4     Collection<LifecycleElement> destroyMethodsToUse =
     5             (checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);
     6     if (!destroyMethodsToUse.isEmpty()) {
     7         for (LifecycleElement element : destroyMethodsToUse) {
     8             if (logger.isTraceEnabled()) {
     9                 logger.trace("Invoking destroy method on bean '" + beanName + "': " + element.getMethod());
    10             }
    11             // 调用对应的销毁方法
    12             element.invoke(target);
    13         }
    14     }
    15 }
  • 相关阅读:
    记一次dba面试
    MySQL登陆 socket 问题
    推荐一些MySQL的博文(持续更新)
    MySQL 参数调优工具--tuning-primer
    当扫描的数据超过了全表的17%就不使用索引
    MySQL 5.7 新增参数
    MySQL 5.7 和 MySQL 5.6参数默认值比较
    MySQL创建的用户无法从本地登陆
    含有IN的子查询
    索引大小对语句执行速度的影响
  • 原文地址:https://www.cnblogs.com/h--d/p/14656012.html
Copyright © 2011-2022 走看看