zoukankan      html  css  js  c++  java
  • Spring源码学习(六)-spring初始化回调方法源码学习

    1.spring官方指定了三种初始化回调方法
      1.1、@PostConstruct、@PreDestory
      1.2、实现 InitializingBean DisposableBean 接口
      1.3、设置init-method和destory-method
      三种方式的优先级从高到低
    在spring官方文档里面有明确指出
    1 Multiple lifecycle mechanisms configured for the same bean, with 
    2     different initialization methods, are called as follows:
    3       Methods annotated with @PostConstruct
    4       afterPropertiesSet() as defined by the InitializingBean callback interface
    5      A custom configured init() method
    6     Destroy methods are called in the same order:
    7       Methods annotated with @PreDestroy
    8       destroy() as defined by the DisposableBean callback interface
    9       A custom configured destroy() method 

    2.三种配置初始化bean的方式,调用时机不同,对于注解,是在spring生命周期中第七个bean后置处理器调用的时候,由CommonAnnotationBeanPostProcessor的postProcessBeforeInitialization()方法来处理

    而剩下的两种是在 第七个bean后置处理器执行之后的下一行代码中执行的 
     
    3.@PostConstruct和@PreDestroy源码 
      3.1、在spring生命周期中,第三个后置处理器方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors;在CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,调用了buildLifecycleMetadata()方法,有一段比较重要的代码: 
      
     1 do {
     2   final List<LifecycleElement> currInitMethods = new ArrayList<>();
     3   final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
     4 
     5   ReflectionUtils.doWithLocalMethods(targetClass, method -> {
     6     //如果目标类中的方法,添加了@PostConstruct注解,就添加到currInitMethods
     7     if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
     8       LifecycleElement element = new LifecycleElement(method);
     9       currInitMethods.add(element);
    10       if (logger.isTraceEnabled()) {
    11         logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
    12       }
    13     }
    14     //如果目标类的方法,添加了@PreDestory注解,就添加到currDestroyMethod中
    15     if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
    16       currDestroyMethods.add(new LifecycleElement(method));
    17       if (logger.isTraceEnabled()) {
    18         logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
    19       }
    20     }
    21   });
    22 
    23   initMethods.addAll(0, currInitMethods);
    24   destroyMethods.addAll(currDestroyMethods);
    25   targetClass = targetClass.getSuperclass();
    26 }
    27 while (targetClass != null && targetClass != Object.class);

    这里,最终会根据initMethods和destroyMethods来初始化一个LifecycleMetadata对象,然后再把new出来的元对象,存到了一个map中 lifecycleMetadataCache 
     
     1 private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
     2   if (this.lifecycleMetadataCache == null) {
     3     // Happens after deserialization, during destruction...
     4     return buildLifecycleMetadata(clazz);
     5   }
     6   // Quick check on the concurrent map first, with minimal locking.
     7   LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
     8   if (metadata == null) {
     9     synchronized (this.lifecycleMetadataCache) {
    10       metadata = this.lifecycleMetadataCache.get(clazz);
    11       if (metadata == null) {
    12         metadata = buildLifecycleMetadata(clazz);
    13         this.lifecycleMetadataCache.put(clazz, metadata);
    14       }
    15       return metadata;
    16     }
    17   }
    18   return metadata;
    19 }

      3.2、在spring生命周期的第七个后置处理器方法中,org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
    会尝试先从lifecycleMetadataCache中根据class,获取到元对象,然后调用元对象的 invokeInitMethods()方法 
      
     1 public void invokeInitMethods(Object target, String beanName) throws Throwable {
     2     Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
     3     Collection<LifecycleElement> initMethodsToIterate =
     4         (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
     5     if (!initMethodsToIterate.isEmpty()) {
     6       boolean debug = logger.isDebugEnabled();
     7       for (LifecycleElement element : initMethodsToIterate) {
     8         if (debug) {
     9           logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
    10         }
    11         element.invoke(target);
    12       }
    13     }
    14   }

    这里的element.invoke()就是调用bean中添加了@PostConstruct注解的方法(method.invoke())
    @PreDestory注解的原理是一样的,只是调用时机是在调用annotationConfigApplicationContext.close()方法的时候,会调用
    org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction 
     
    4.剩下的两种初始化方法,执行处理逻辑,是在一块代码中 
     
    //在调用第七个后置处理器的下一行,是这个代码
      try {
        invokeInitMethods(beanName, wrappedBean, mbd);
      } 
      
     1 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
     2       throws Throwable {
     3 
     4   //判断当前bean是否是 InitializingBean接口的实现类,如果是,判断是否实现了 afterPropertiesSet() 方法
     5   boolean isInitializingBean = (bean instanceof InitializingBean);
     6   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
     7     if (logger.isTraceEnabled()) {
     8       logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
     9     }
    10     if (System.getSecurityManager() != null) {
    11       try {
    12         AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    13           ((InitializingBean) bean).afterPropertiesSet();
    14           return null;
    15         }, getAccessControlContext());
    16       }
    17       catch (PrivilegedActionException pae) {
    18         throw pae.getException();
    19       }
    20     }
    21     else {
    22       ((InitializingBean) bean).afterPropertiesSet();
    23     }
    24   }
    25 
    26   //如果是在@Bean中配置了init-method和destroy-method,那执行的是这里的方法
    27   if (mbd != null && bean.getClass() != NullBean.class) {
    28     String initMethodName = mbd.getInitMethodName();
    29     if (StringUtils.hasLength(initMethodName) &&
    30         !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
    31         !mbd.isExternallyManagedInitMethod(initMethodName)) {
    32       invokeCustomInitMethod(beanName, bean, mbd);
    33     }
    34   }
    35 }

      对于在@Bean注解指定init-method方式的,是在将class扫描到beanDefinition的时候,会对@Bean这种方式的bean进行处理
        loadBeanDefinitionsForBeanMethod(beanMethod);在这里会设置bean的initMethod
      spring扫描bean,将class扫描到beanDefinitionMap中有三种方式;
        @ComponentScan注解
        @Import
            importBeanDefinitionRegistrar
            importSelector
        @Bean 
     
     
    5.对于销毁方法,还没仔细研究,后面了解之后,再做补充: 
     
      
     1 public void destroy() {
     2     //这里是处理@PreDestroy注解的销毁方法
     3     if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
     4         for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
     5             processor.postProcessBeforeDestruction(this.bean, this.beanName);
     6         }
     7     }
     8 
     9     if (this.invokeDisposableBean) {
    10         if (logger.isTraceEnabled()) {
    11             logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
    12         }
    13         try {
    14             if (System.getSecurityManager() != null) {
    15                 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    16                     ((DisposableBean) this.bean).destroy();
    17                     return null;
    18                 }, this.acc);
    19             }
    20             else {
    21                 //这里是处理 DisposableBean 接口实现类中destroy()销毁方法的逻辑
    22                 ((DisposableBean) this.bean).destroy();
    23             }
    24         }
    25         catch (Throwable ex) {
    26             String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
    27             if (logger.isDebugEnabled()) {
    28                 logger.warn(msg, ex);
    29             }
    30             else {
    31                 logger.warn(msg + ": " + ex);
    32             }
    33         }
    34     }
    35 
    36     //这是处理@Bean中 destory-method这种方式的销毁方法
    37     if (this.destroyMethod != null) {
    38         invokeCustomDestroyMethod(this.destroyMethod);
    39     }
    40     else if (this.destroyMethodName != null) {
    41         Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
    42         if (methodToInvoke != null) {
    43             invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
    44         }
    45     }
    46 }
     
  • 相关阅读:
    LeetCode 876——链表的中间结点
    LeetCode 206——反转链表
    一次漫长的代码复现经历
    在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现
    编译 TensorFlow 的 C/C++ 接口
    TensorFlow 同时调用多个预训练好的模型
    在 C/C++ 中使用 TensorFlow 预训练好的模型—— 间接调用 Python 实现
    TensorFlow 调用预训练好的模型—— Python 实现
    Python 学习笔记之 Numpy 库——文件操作
    Python 学习笔记之 Numpy 库——数组基础
  • 原文地址:https://www.cnblogs.com/mpyn/p/12134041.html
Copyright © 2011-2022 走看看