Spring源码解析——Bean销毁的生命周期

使用

首先我们先来回顾一下 Spring 初始化/销毁 Bean 几种方式,分别为:

  • init-method/destroy-method
  • InitializingBean/DisposableBean
  • @PostConstruct/@PreDestroy
  • ContextStartedEvent/ContextClosedEvent

init-method/destroy-method
这种方式在配置文件文件指定初始化/销毁方法。XML 配置如下

<bean id="demoService" class="com.dubbo.example.provider.DemoServiceImpl"  destroy-method="close"  init-method="initMethod"/>

或者也可以使用注解方式配置:

@Configurable
public class AppConfig {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public HelloService hello() {
        return new HelloService();
    }
}

InitializingBean/DisposableBean
这种方式需要继承 Spring 接口 InitializingBean/DisposableBean,其中 InitializingBean 用于初始化动作,而 DisposableBean 用于销毁之前清理动作。使用方式如下:

@Service
public class HelloService implements InitializingBean, DisposableBean {
    
    @Override
    public void destroy() throws Exception {
        System.out.println("hello destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("hello init....");
    }
}

@PostConstruct/@PreDestroy
这种方式相对于上面两种方式来说,使用方式最简单,只需要在相应的方法上使用注解即可。使用方式如下:

@Service
public class HelloService {


    @PostConstruct
    public void init() {
        System.out.println("hello @PostConstruct");
    }

    @PreDestroy
    public void PreDestroy() {
        System.out.println("hello @PreDestroy");
    }
}

ContextStartedEvent/ContextClosedEvent
这种方式使用 Spring 事件机制,日常业务开发比较少见,常用与框架集成中。Spring 启动之后将会发送 ContextStartedEvent 事件,而关闭之前将会发送 ContextClosedEvent 事件。我们需要继承 Spring ApplicationListener 才能监听以上两种事件。

@Service
public class HelloListener implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof ContextClosedEvent){
            System.out.println("hello ContextClosedEvent");
        }else if(event instanceof ContextStartedEvent){
            System.out.println("hello ContextStartedEvent");
        }

    }
}

也可以使用 @EventListener注解,使用方式如下:

public class HelloListenerV2 {
 
  @EventListener(value = {ContextClosedEvent.class, ContextStartedEvent.class})
    public void receiveEvents(ApplicationEvent event) {
        if (event instanceof ContextClosedEvent) {
            System.out.println("hello ContextClosedEvent");
        } else if (event instanceof ContextStartedEvent) {
            System.out.println("hello ContextStartedEvent");
        }
    }
}

PS:只有调用 ApplicationContext#start 才会发送 ContextStartedEvent。若不想这么麻烦,可以监听 ContextRefreshedEvent 事件代替。一旦 Spring 容器初始化完成,就会发送 ContextRefreshedEvent。

bean销毁

当容器进行关闭的时候需要对bean和bean工厂以及一系列的容器进行销毁,这个时候销毁只是对容器的bean对象进行销毁,不意味着对对象进行销毁;销毁分为两种,手动销毁自动销毁,手动销毁需要调用容器的close方法进行销毁,而自动销毁是向jvm注册一个钩子线程,当容器进行关闭的时候会自动调用销毁的钩子线程进行销毁,比如我们的jvm关闭的时候会自动来调用你的钩子线程来销毁容器的bean,我们来看自动会手动的方式。

手动方式:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		System.out.println(applicationContext.getBean("userService"));

		applicationContext.close();

自动方式:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		System.out.println(applicationContext.getBean("userService"));
		//jvm钩子
		applicationContext.registerShutdownHook();

//-------------------------------------------------------------------------
public void registerShutdownHook() {
		//向JVM运行时注册一个关闭链接,在JVM关闭时关闭这个上下文,除非此时它已经关闭。
		//托给 doClose() 方法去关闭,用于实际的关闭过程。
		if (this.shutdownHook == null) {
			// No shutdown hook registered yet.
			// 尚未注册关机链接
			this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
				@Override
				public void run() {
					synchronized (startupShutdownMonitor) {
						doClose();
					}
				}
			};
			Runtime.getRuntime().addShutdownHook(this.shutdownHook);
		}
	}

原理

在进行Bean的销毁时候,调用的是doClose方法

protected void doClose() {
		// Check whether an actual close attempt is necessary...
		if (this.active.get() && this.closed.compareAndSet(false, true)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Closing " + this);
			}

			LiveBeansView.unregisterApplicationContext(this);

			try {
				// Publish shutdown event.
				//发布事件监听器
				publishEvent(new ContextClosedEvent(this));
			}
			catch (Throwable ex) {
				logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
			}

			// Stop all Lifecycle beans, to avoid delays during individual destruction.
			// 停止所有 Lifecycle bean,以避免单个地销毁期间而产生延迟。
			if (this.lifecycleProcessor != null) {
				try {
					this.lifecycleProcessor.onClose();
				}
				catch (Throwable ex) {
					logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
				}
			}

			// Destroy all cached singletons in the context's BeanFactory.
			//销毁单例bean
			destroyBeans();

			// Close the state of this context itself.
			//关闭工厂,设置beanFactory为null
			closeBeanFactory();

			// Let subclasses do some final clean-up if they wish...
			onClose();

			// Reset local application listeners to pre-refresh state.
			//清除所有的监听器
			if (this.earlyApplicationListeners != null) {
				this.applicationListeners.clear();
				this.applicationListeners.addAll(this.earlyApplicationListeners);
			}

			// Switch to inactive.
			//将容器设置为非激活
			this.active.set(false);
		}
	}

这里重点来分析下destroyBeans销毁bean的过程

protected void destroyBeans() {
   getBeanFactory().destroySingletons();
}

//---------------------------------------------------------------------

public void destroySingletons() {
    //销毁单例池
    super.destroySingletons();
	// 清空manualSingletonNames集合
	updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
	// 情况其他集合
	clearByTypeCache();
}

//-------------------------------------------------------------

public void destroySingletons() {
   if (logger.isTraceEnabled()) {
      logger.trace("Destroying singletons in " + this);
   }
   synchronized (this.singletonObjects) {
      this.singletonsCurrentlyInDestruction = true;
   }

   //拿到所有的销毁方法,就是在spring的bean中定义了销毁bean的时候需要回调的
   //方法;disposableBeans中包含的销毁方法有三种:
   //1.实现了DisposableBean和AutoCloseable(java的接口)
   //2.用xml或者@Bean定义的bean都有一个destroyMethod默认的方法,这个默认的方法是不要实现的,直接回调用
   //比如会自动调用bean中的close 、shutdown方法
   //3.使用了注解  @PreDestroy注册的方法
   //4.在BeanDefinition中手动添加了或者xml中手动配置的销毁方法
   String[] disposableBeanNames;
   //拿到所有的disposableBeans销毁方法
   synchronized (this.disposableBeans) {
      disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
   }
   //循环进行销毁
   for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
      destroySingleton(disposableBeanNames[i]);
   }

   this.containedBeanMap.clear();
   this.dependentBeanMap.clear();
   this.dependenciesForBeanMap.clear();

   clearSingletonCache();
}

//----------------------------------------------------------------

public void destroySingleton(String beanName) {
   // Remove a registered singleton of the given name, if any.
   //将这个bean从单例池中移除,一二级缓存中移除,还有就是一些spring内部容器的缓存中全部移除
   removeSingleton(beanName);

   // Destroy the corresponding DisposableBean instance.
   DisposableBean disposableBean;
   synchronized (this.disposableBeans) {
      //disposableBeans是一个map,为什么它可以直接转成DisposableBean,在map中的对象类型是object
      //其实这里使用的是适配器模式,这个要在加入这个bean的时候才能知道是什么原理
      disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
   }
   destroyBean(beanName, disposableBean);
}

//-------------------------------------------------------------------

protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
   // Trigger destruction of dependent beans first...
   Set<String> dependencies;
   //在依赖bean的map中移除
   synchronized (this.dependentBeanMap) {
      // Within full synchronization in order to guarantee a disconnected Set
      dependencies = this.dependentBeanMap.remove(beanName);
   }
   if (dependencies != null) {
      if (logger.isTraceEnabled()) {
         logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
      }
      //这里是一个递归调用,就是如果这个bean在容器中有依赖的bean,那么在移除这个bean前,要先把依赖的bean全部移除,
      //递归调用destroySingleton方法进行移除
      for (String dependentBeanName : dependencies) {
         destroySingleton(dependentBeanName);
      }
   }

   // Actually destroy the bean now...
   if (bean != null) {
      try {
         /**
          * 这里才是调用销毁的方法,但是如果你这样认为,你就错了,你想哈,我们的
          * disposableBeans是value是一个Object,那么取出来的就直接转成DisposeBean,然后调用destory方法
          * 但是你没有没想过,刚刚在前面说的disposableBeans这个bean中存在不同的销毁方法,如果是xml或者@Bean的方式
          * 那么默认方法是close、shutdown或者BeanDefinition中指定的默认方法
          * 所以这里直接调用destroy不是直接调用的我们bean中的销毁方法,这里使用的是适配器模式
          * 就是说在添加到disposableBeans的时候,将销毁的bean封装成一个对象,然后这个对象实现了DisposeBean的方法
          * 每次调用销毁其实是调用到了适配器中的destroy方法,适配器中根据销毁方法的类型去调用指定的销毁方法
          * DisposableBeanAdapter.destroy()
          */
         bean.destroy();
      }
      catch (Throwable ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
         }
      }
   }

   // Trigger destruction of contained beans...
   Set<String> containedBeans;
   synchronized (this.containedBeanMap) {
      // Within full synchronization in order to guarantee a disconnected Set
      containedBeans = this.containedBeanMap.remove(beanName);
   }
   if (containedBeans != null) {
      for (String containedBeanName : containedBeans) {
         destroySingleton(containedBeanName);
      }
   }

   // Remove destroyed bean from other beans' dependencies.
   synchronized (this.dependentBeanMap) {
      for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
         Map.Entry<String, Set<String>> entry = it.next();
         Set<String> dependenciesToClean = entry.getValue();
         dependenciesToClean.remove(beanName);
         if (dependenciesToClean.isEmpty()) {
            it.remove();
         }
      }
   }

   // Remove destroyed bean's prepared dependency information.
   this.dependenciesForBeanMap.remove(beanName);
}

上面的代码中我们重点来看destroyBean销毁bean的方法,就是对spring在启动和创建的过程设置好多的map和集合对象,这些对象都会有用的,所以在创建的过程是没有销毁的,这里需要销毁。不是太重要,重要的是把destroyBean这个方法的逻辑弄清楚;
在上面的代码中有一个缓存非常重要disposableBeans,这个集合缓存存储了就是每个bean中定义的所有的销毁方法,这些销毁方法包括了很多,具体包括了:

  1. BeanDefinition中定义的或者xml中定义销毁方法;
  2. @Bean中定义的默认销毁方法;
  3. 实现了DisposableBean,AutoCloseable而需要实现了销毁方法;
  4. @PreDestroy定义的销毁方法

所以这个缓存集合disposableBeans中存储了每个bean对应的这些销毁方法,但是要你的bean定义了这些中的一个或者多个销毁方法,disposableBeans集合缓存中才会有,而我们看到disposableBeans这个map其实是一个<String,Object>的形式,上面的这些销毁的方法的对象类型可能都不一样,而其实你看循环取销毁的对象调用destroy方法的时候是这样写的:

synchronized (this.disposableBeans) {
   //disposableBeans是一个map,为什么它可以直接转成DisposableBean,在map中的对象类型是object
   //其实这里使用的是适配器模式,这个要在加入这个bean的时候才能知道是什么原理
   disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
}

直接强制转换的,其实disposableBeans中添加value的时候这个value是一个适配器,也就是说销毁bean使用的是适配器模式,将上面的所有的销毁方法的实现都封装在了一个适配器中,当你调用适配器的销毁方法时,适配器会根据当前bean中定义的销毁方法类型来调用,就是你定义了3个就调用3个,所以spring在销毁这一块采用的是适配器模式,不晓得这样说大家能不能够懂它设计的原理;
我们来看destroyBean方法的bean.destroy()这里,首先bean是DisposableBean,DisposableBean中是存在销毁方法destroy的,上面我已经说了销毁这里是采用的适配器设计模式,所以这里的destroy方法不是调用DisposableBean的销毁方法,而是调用了适配器的destroy方法,而这个适配器是DisposableBean的子类,所以这些在java中是可以的,而这个适配器是什么呢?它就是DisposableBeanAdapter,它的定义如下:

/**
 * 反正spring在销毁bean的这块,销毁bean前会将每个bean中定义的销毁方法都通过则适配器进行注册
 * 也就是说某个bean中有三个销毁的方法,
  *不管这三个销毁的方法是在BeanDefinition中定义的,还是默认指定的
 * 都会封装到这个适配器中,然后放入到缓存中,当容器关闭的时候,那么就会找到这个销毁的缓存集合,然后循环调用来执行销毁的方法
 */
@SuppressWarnings("serial")
class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {

   //当定义的bean的销毁方法模式是(inferred)的时候,那么销毁的默认方法就是close或者shutdown,spring会自动匹配
   private static final String CLOSE_METHOD_NAME = "close";

   private static final String SHUTDOWN_METHOD_NAME = "shutdown";

   private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class);


   private final Object bean;

   private final String beanName;

   private final boolean invokeDisposableBean;

   private final boolean nonPublicAccessAllowed;
   ......

这里先看看disposableBeans这个map是在哪里添加进去的,在Bean的初始化方法doCreateBean中,在初始化完Bean后最后面会调用registerDisposableBeanIfNecessary(beanName, bean, mbd);也就是在这个方法完成的填充

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		//这里判断是销毁的方法所在的bean是单例的,并且符合条件的才能加入到销毁方法的队列中

		if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
			if (mbd.isSingleton()) {
				//满足条件就将一系列的销毁方法封装到销毁bean的适配器中,这里就是使用的适配器模式
				//在容器关闭的时候,就会获取disposableBeans这集合,这个集合里面就存储了DisposableBeanAdapter
				//而这个DisposableBeanAdapter又是DisposeBean的子类,所以DisposableBeanAdapter重写了
				//DisposeBeann的destory方法,那么在容器close的时候会调用DisposableBeanAdapter的destory方法
				//在DisposableBeanAdapter中会根据是那种destory类型去调用指定的销毁方法
				/**
				 * 比如:
				 * 1.BeanDefinition中的定义的销毁方法(包括手动定义和自动默认定义的)
				 * 2.实现了DisposeBean或者AutoClosed接口的销毁方法
				 * 3.后置处理器中实现了的销毁方法,在后置处理器InitDestroyBeanPostProcessor找到的@PostConstruct
				 * 或者@preDestroy注解的方法
				 * 这些销毁方法都会在容器调用DisposableBeanAdapter这种的destroy方法是去判断是那种销毁方法从而调用
				 */
				registerDisposableBean(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
			else {
				// A bean with a custom scope...
				Scope scope = this.scopes.get(mbd.getScope());
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
				}
				scope.registerDestructionCallback(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
		}
	}

这里关注两个点,一个条件判断,第二个DisposableBeanAdapter的构造方法

protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
   /**
    * 这里的判断分了好几块
    * 1.首先这个bean不能使NullBean
    * 2.bean中需要包含destroy方法
    * 3.后置处理器中包含了destory方法,也就是通过@PreDestory注解的方法
    * 4.如果实现了InitDestroyAnnotationBeanPostProcessor生命周期回调的接口,那么是会有初始化的方法和销毁方法
    * spring默认添加了InitDestroyAnnotationBeanPostProcessor这个后置处理器,而这个后置处理器是表示
    * 如果找到了@PreDestroy注解的方法也会返回true(这个判断很简单,判断是否是实现了DestructionAwareBeanPostProcessor
    * 这个后置处理器,如果实现了,那么就去生命周期回调的销毁缓存中找,如果找到了销毁方法,那么就表示有销毁方法)
    * 反正逻辑都比较严谨,需要你结合上下文来理解
    */
   return (bean.getClass() != NullBean.class &&
         (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&
               DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
}
/**
 * Check whether the given bean has any kind of destroy method to call.
 * @param bean the bean instance
 * @param beanDefinition the corresponding bean definition
 *  这个是判断是否有销毁方法的代码逻辑
 *  分为两段逻辑:
 *  1.如果实现了   DisposableBean或者AutoCloseable则直接返回;
 *  2.否则看是否有初始化方法,这个初始化方法是从BeanDefinition中获取的getDestroyMethodName
 *   如果getDestroyMethodName是默认的   (inferred),则判断是否有close或者shutdown方法,有的话返回true
 *                       否则直接返回程序员手动设置的初始化方法
 */
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
   //如果bean实现了DisposableBean或者AutoCloseable则表示这个bean有销毁的方法,直接返回true
   if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
      return true;
   }
   /**
    * 否则进入下面的逻辑
    * 首先获取BeanDefinition中的销毁方法,如果这个销毁方法不为空,一般在xml中或者@Bean可以设置一个销毁方法
    * 在xml中要自己去设置销毁方法,而@Bean如果你不设置,会生成一个默认的方法
    * String destroyMethod() default AbstractBeanDefinition.INFER_METHOD
    * 还有一个地方可以设置,前面说了有一个bean的后置处理器,叫合并bean的后置处理器
    * 只要你实现了MergedBeanDefinitionPostProcessor,那么你可以实现它的方法
    * postProcessMergedBeanDefinition来获取BeanDefinition设置销毁和初始化方法
    * 这里的判断
    * 1.首先如果destroyMethodName==‘(inferred)’,那么就只需要在bean中添加一个close或者shutdown的方法
    * 那么spring的销毁的时候会自动调用close或者shutdown方法
    */
   String destroyMethodName = beanDefinition.getDestroyMethodName();
   if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
      return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
            ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
   }
   return StringUtils.hasLength(destroyMethodName);
}
 

上面的代码的意思就是符合哪些条件的可以加入到销毁方法缓存列表的条件,我总结了下:

  1. 实现了DisposableBean的bean;
  2. BeanDefinition中添加了销毁方法;
  3. @Bean中添加的默认方法((inferred));
  4. @PreDestroy注解方法;

我们再看下销毁的适配器DisposableBeanAdapter的具体实现细节

public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
      List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {

   Assert.notNull(bean, "Disposable bean must not be null");
   //销毁方法所在的bean对象
   this.bean = bean;
   this.beanName = beanName;
   //这个属性invokeDisposableBean是表示你的销毁方法是否是实现了DisposableBean并且bean中存在destroy方法
   this.invokeDisposableBean =
         (this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
   //是否允许非public的构造或者普通方法执行
   this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
   this.acc = acc;
   //inferDestroyMethodIfNecessary是找到BeanDefinition中定义的销毁方法或者是默认定义的close或者shutdown方法,也或者是
   //实现了AutoClosed中的close方法
   String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
   /**
    * 这个if条件的意思就是说:在上面找到的销毁方法不为空,并且bean没有实现了DisposableBean以及bean中不包含destroy方法
    * 和BeanDefinition中包含上面找到的方法,那么这个条件到底是什么意思呢?
    * 意思就是找到没有实现DisposableBean并且又可能实现了Autoclosed或者定义了默认的销毁方法:
    * 1.实现了AutoClosed的销毁方法close
    * 2.定义了当BeanDefinition中销毁方法是(inferred)中的close或者shutdown方法
    * 3.BeanDefinition中定义了销毁方法
    */
   if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
         !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
      this.destroyMethodName = destroyMethodName;
      //找到这个方法
      Method destroyMethod = determineDestroyMethod(destroyMethodName);
      if (destroyMethod == null) {
         if (beanDefinition.isEnforceDestroyMethod()) {
            throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
                  destroyMethodName + "' on bean with name '" + beanName + "'");
         }
      }
      else {
         //这边定义了销毁方法的参数只能为一个,并且不能是Boolean的参数
         Class<?>[] paramTypes = destroyMethod.getParameterTypes();
         if (paramTypes.length > 1) {
            throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                  beanName + "' has more than one parameter - not supported as destroy method");
         }
         else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
            throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                  beanName + "' has a non-boolean parameter - not supported as destroy method");
         }
         destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
      }
      this.destroyMethod = destroyMethod;
   }
   //这里是找到后置处理器中定义的销毁方法,也就是@PreDestroy
   this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
   /**
    * 这个方法的大概意思就是找到BeanDefinition中定义了销毁方法或者spring为bean生成的默认销毁方法或者是实现了AutoCloseable
    * 下面的if两个判断,第一个if判断默认的方法是否是“(inferred)”,如果默认的方法是(inferred),那么代表是spring默认产生的
    * spring默认产生的情况下会自动识别close和shutdown
    * 如果第一个条件不满足,那么就看下是否实现了AutoCloseable,这个条件的前置条件是BeanDefinition中没有定义销毁的方法,如果定义了
    * 就直接返回直接定义的默认销毁方法,否则检查是否实现了AutoCloseable接口,记住的是AutoCloseable中的默认实现关闭方法也是close
    * 所以第二个条件只需要判断BeanDefinition中没有定义销毁方法但是bean实现了AutoCloseable的情况下
    * 会去看下这个bean中有没有close或者shutdown方法
    * 那么我们可以得出一个结论就是:
    * 1.当BeanDefinition中定义了初始化方法和实现了
    * AutoCloseable或的情况下,只会执行BeanDefinition中定义的销毁方法
    * 2.当BeanDefinition中定义了初始化方法和实现了
    * DisposableBean或的情况下,都会执行
    */
   String destroyMethodName = beanDefinition.getDestroyMethodName();
   if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
         (destroyMethodName == null && bean instanceof AutoCloseable)) {
      // Only perform destroy method inference or Closeable detection
      // in case of the bean not explicitly implementing DisposableBean
      if (!(bean instanceof DisposableBean)) {
         try {
            return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
         }
         catch (NoSuchMethodException ex) {
            try {
               return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
            }
            catch (NoSuchMethodException ex2) {
               // no candidate destroy method found
            }
         }
      }
      return null;
   }
   return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}

上面的构造就是在注册销毁集合缓存的时候调用的构造方法,其实这个构造简单来说就是我上面写的很清楚的就是将哪几种销毁的类型定义好,等spring调用销毁的时候,适配器才能知道你的bean中定义了那些销毁的方法,需要怎么来调用,比如你定义了3个,那么这3个是否符合条件可以在销毁的时候被调用,上面的代码简单来说就是:
1.如果实现了DisposableBean ,单独拿出来;
2.后置处理器的@PreDstroy的单独拿出来;
3.实现了AutoCloseable和spring默认生成的销毁方法以及BeanDefinition中定义的销毁方法单独拿出来,分为三类做好记录(因为spring默认创建的销毁方法是close或者shutdown,而AutoCloseable实现的接口方法也是close,所以我猜spring这里是单独拿出来的)。

最后再看看DisposableBeanAdapter.destroy()

/**
 * 这个是适配器中的销毁方法
 * 这个销毁方法处理的是所有的销毁方法
 * 销毁方法有:
 * 1.BeanDefinition中手动定义的
 * 2.@Bean或者xml中定义的默认销毁方法
 * 3.@PreDestroy定义的销毁方法
 * 4.实现了DisposableBean或者Autoclosed的销毁方法
 *
 */

@Override
public void destroy() {
   //这里调用的是销毁bean的后置处理器中定义的销毁方法,也就是@PreDestroy注解的销毁方法
   if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
      for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
         processor.postProcessBeforeDestruction(this.bean, this.beanName);
      }
   }

   //这里调用实现了DisposableBean中的销毁方法,实现了DisposableBean的方法是destroy
   if (this.invokeDisposableBean) {
      if (logger.isTraceEnabled()) {
         logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
      }
      try {
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
               ((DisposableBean) this.bean).destroy();
               return null;
            }, this.acc);
         }
         else {
            ((DisposableBean) this.bean).destroy();
         }
      }
      catch (Throwable ex) {
         String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
         if (logger.isDebugEnabled()) {
            logger.warn(msg, ex);
         }
         else {
            logger.warn(msg + ": " + ex);
         }
      }
   }

   /**
    * 下面就是处理
    * 1.BeanDefinition中或者xml手动定义的销毁方法
    *     2.@Bean中定义的默认销毁方法
    *     3.实现了AutoClosed的销毁close方法
    */
   if (this.destroyMethod != null) {
      invokeCustomDestroyMethod(this.destroyMethod);
   }
   else if (this.destroyMethodName != null) {
      Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
      if (methodToInvoke != null) {
         invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
      }
   }

总结

在这里插入图片描述

参考

https://blog.csdn.net/scjava/article/details/109276324
https://zhuanlan.zhihu.com/p/54215879
https://www.cnblogs.com/cxyAtuo/p/11665518.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值