bean生命周期源码(三)

书接上文

文章目录

    • 一、Bean的销毁逻辑
      • 1. 简介
      • 2. Bean销毁逻辑的注册
      • 3. Bean的销毁过程

一、Bean的销毁逻辑

1. 简介

前面我们已经分析完了Spring创建Bean的整个过程的源码,在创建bean的核心方法中doCreateBean这一个核心方法中,在方法的最后面有这么一段代码:

	// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;

这个registerDisposableBeanIfNecessary方法就是销毁bean的逻辑,下面我们就详细分析一下销毁Bean的过程。

2. Bean销毁逻辑的注册

在使用bean的销毁逻辑时,我们可以像下面代码一样:

@Component
public UserService implements DisposedBean{
	@Autowired
	private OrderService orderservice;

	@Override
	public void destroy() throws Exception{
		//业务逻辑
	}
}

@Component
public UserService{
	@Autowired
	private OrderService orderservice;

	@preDestroy
	public void destroy() throws Exception{
		//业务逻辑
	}
}

上面代码的逻辑就是让我们的UserService实现了DisposedBean接口,并实现了destroy方法,或者直接在指定方法上加上@preDestroy注解,那么这个方法会在UserService被销毁时调用。

注意所谓的销毁并不是JVM将我们的bean对象销毁,我们知道JVM在垃圾回收的过程中,会回收销毁掉垃圾对象,但调用destroy方法在对象销毁时被调用这一个逻辑JVM是不能帮我们实现的,JVM在只会在销毁对象是调用默认的finalize方法,那么这个销毁方法会在什么时候被调用?其实是在我们的Spring容器销毁时被调用。

下面我们给了两种关闭bean容器的方法:

  • 手动关闭
public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
		applicationContext.close();
	}

直接调用close()方法实现容器的关闭。

  • 向JVM注册关闭钩子
public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();
		applicationContext.registerShutdownHook();
	}

applicationContext.registerShutdownHook() 是用来注册一个JVM关闭钩子(shutdown hook)。在Java中,当JVM即将关闭时,会执行一些预定义的动作。通过注册关闭钩子,你可以指定在JVM关闭之前执行一些特定的操作。具体地说,registerShutdownHook()会注册一个钩子,以确保在JVM关闭时,Spring容器执行销毁和清理工作。这包括关闭所有的单例bean、释放资源等。这样可以确保在应用程序关闭时,Spring能够做一些必要的清理,以避免资源泄漏或其他问题。

下面是这两种方式的源码:

@Override
	public void close() {
		synchronized (this.startupShutdownMonitor) {
			doClose();
			// If we registered a JVM shutdown hook, we don't need it anymore now:
			// We've already explicitly closed the context.
			if (this.shutdownHook != null) {
				try {
					Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
				}
				catch (IllegalStateException ex) {
					// ignore - VM is already shutting down
				}
			}
		}
	}

@Override
	public void registerShutdownHook() {
		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);
		}
	}

可以发现这两种方式底层其实都是调用的doClose()方法。

继续回到registerDisposableBeanIfNecessary方法

// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;

该方法接收3个参数,分别是beanname,初始化后的bean以及beandefintion,我们进去看看它的源码:

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
			if (mbd.isSingleton()) {
				// Register a DisposableBean implementation that performs all destruction
				// work for the given bean: DestructionAwareBeanPostProcessors,
				// DisposableBean interface, custom destroy method.
				registerDisposableBean(beanName, new DisposableBeanAdapter(
						bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, 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, getBeanPostProcessorCache().destructionAware, acc));
			}
		}
	}

首先if (!mbd.isPrototype() && requiresDestruction(bean, mbd))会判断你的bean是否是单例的,如果是单例的它会执行requiresDestruction(bean, mbd)来判断你这个bean到底需不需要执行销毁前的逻辑。

	protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
		return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
				(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
						bean, getBeanPostProcessorCache().destructionAware))));
	}

上面方法通过DisposableBeanAdapter.hasDestroyMethod(bean, mbd)来判断你这个方法有没有所谓的销毁逻辑。下面我们看看它是怎样去判断的。

	public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
		if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
			return true;
		}
		return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
	}

如果你的Bean实现了DisposableBean和AutoClosedable接口,就返回true,否则执行方法inferDestroyMethodIfNecessary

@Nullable
	private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
	    //看看你的beanDefinition有没有销毁方法
		String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
		if (destroyMethodName == null) {
		    //获得你beanDefinition中配置销毁方法的名称
			destroyMethodName = beanDefinition.getDestroyMethodName(); //
			//如果你在beanDefinition中的设置的方法(通常是通过实现BeanPostProcess接口中设置的)名为INFER_METHOD,则执行小面的逻辑
			if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
					(destroyMethodName == null && bean instanceof AutoCloseable)) {
				destroyMethodName = null;
				if (!(bean instanceof DisposableBean)) {
					try {
					//就会获取你定义的close方法来作为销毁方法
						destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
					}
					catch (NoSuchMethodException ex) {
						try {
				    //或者将你定义的ShutDown方法作为销毁方法
							destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
						}
						catch (NoSuchMethodException ex2) {
							// no candidate destroy method found
						}
					}
				}
			}
			beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
		}
		return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
	}

上面代码中的if (destroyMethodName == null) {这个代码块中的逻辑可能比较难以理解,下面我用案例来分析一下,如下面代码:

@Component
public class UserService {

	@Autowired
	private OrderService orderService;

	public void test(){
		System.out.println(orderService);
	}

	public void close(){
		System.out.println("close方法被调用了");
	}

}

上面我们给我们的UserService加上了一个close()方法,然后我们添加一个类加上MergedBeanDefinitionPostProcessorInstantiationAwareBeanPostProcessor

@Component
	public class jackBeanPostProcessor implements InstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
		@Override
		public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
			if(beanName.equals("userService")){
				beanDefinition.setDestroyMethodName("(inferred)");
			}
		}
}

上面代码中我们给beanDefinition设置了一个销毁方法,名字为inferred,也就是前面源码中说的AbstractBeanDefinition.INFER_METHOD这个常量。然后执行下面代码,就会自定调用我们名为close()的方法。

public class Test {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		UserService userService = (UserService) applicationContext.getBean("userService");
		applicationContext.close();
	}
}

在这里插入图片描述
这也就上面那段源码的作用,下面我们接着回到inferDestroyMethodIfNecessary方法,到这里该方法就执行完毕了。然后继续回到requiresDestruction,里面还有一句代码这样的hasDestructionAwareBeanPostProcessors,该方法用来判断容器中有没有bean实现了DestructionAwareBeanPostProcessors接口。

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
	void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
	default boolean requiresDestruction(Object bean) {
		return true;
	}
}

这个接口同样继承了BeanPostProcessor接口,然后它只有两个方法,postProcessBeforeDestruction这个方法就是执行bean销毁前的逻辑,requiresDestruction这个方法就是判断你这个bean需不需要执行销毁方法。

继续回到requiresDestruction方法,如果hasDestructionAwareBeanPostProcessors返回为true,那么就会执行后面的代码DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessorCache().destructionAware))

	public static boolean hasApplicableProcessors(Object bean, List<DestructionAwareBeanPostProcessor> postProcessors) {
		if (!CollectionUtils.isEmpty(postProcessors)) {
			for (DestructionAwareBeanPostProcessor processor : postProcessors) {
				if (processor.requiresDestruction(bean)) {
					return true;
				}
			}
		}
		return false;
	}

首先它会便利我们的destructionAware集合中所有的实现 DestructionAwareBeanPostProcessor接口的bean,然后调用processor.requiresDestruction,判断当前bean需不需要执行销毁方法。

processor.requiresDestruction底层具体实现类,会找到方法前有@preConstruct和@preDestroy注解到方法,然后存入相关的容器。

@Override
	public boolean requiresDestruction(Object bean) {
		return findLifecycleMetadata(bean.getClass()).hasDestroyMethods();
	}

private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
		if (this.lifecycleMetadataCache == null) {
			// Happens after deserialization, during destruction...
			return buildLifecycleMetadata(clazz);
		}

		// Quick check on the concurrent map first, with minimal locking.
		LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
		if (metadata == null) {
			synchronized (this.lifecycleMetadataCache) {
				metadata = this.lifecycleMetadataCache.get(clazz);
				if (metadata == null) {
					metadata = buildLifecycleMetadata(clazz);
					this.lifecycleMetadataCache.put(clazz, metadata);
				}
				return metadata;
			}
		}
		return metadata;
	}

	private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
			return this.emptyLifecycleMetadata;
		}

		List<LifecycleElement> initMethods = new ArrayList<>();
		List<LifecycleElement> destroyMethods = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<LifecycleElement> currInitMethods = new ArrayList<>();
			final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
					LifecycleElement element = new LifecycleElement(method);
					currInitMethods.add(element);
					if (logger.isTraceEnabled()) {
						logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
					}
				}
				if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
					currDestroyMethods.add(new LifecycleElement(method));
					if (logger.isTraceEnabled()) {
						logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
					}
				}
			});

			// 父类的在前面
			initMethods.addAll(0, currInitMethods);
			destroyMethods.addAll(currDestroyMethods);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
				new LifecycleMetadata(clazz, initMethods, destroyMethods));
	}

执行完上面的逻辑,继续回到requiresDestruction方法,这里我们可以总结一下,Spring底层是如何判断我们是否有销毁的逻辑的:

  • 首先判断我们的bean是否实现类AutoCloseableDisposedBean接口,如果实现类了就调用相应的close方法
  • 如果没有实现上面的两个接口,就会判断我们是否修改了BeanDefinition,设置了销毁方法,如果有我们调用自己写的close方法或shutdown方法即可
  • 最后一种逻辑就是,我们时候使用了@PreDestroy注解

如果我们bean具有上面三种中的任何一种逻辑,就说明我们的bean可以执行相应的销毁逻辑,继续回到registerDisposableBeanIfNecessary方法,上面我们已经把if (!mbd.isPrototype() && requiresDestruction(bean, mbd))逻辑执行完了,下面可以进入语句块中了。

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
		//如果我们的bean是单例
			if (mbd.isSingleton()) {
			     
				registerDisposableBean(beanName, new DisposableBeanAdapter(
						bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, 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, getBeanPostProcessorCache().destructionAware, acc));
			}
		}
	}

然后继续执行registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));},这个方法的参数为beanname和创建了一个DisposableBeanAdapter对象。

DisposableBeanAdapter 是 Spring Framework 中的一个内部类,用于帮助处理 bean 的销毁(disposal)操作。在 Spring 容器关闭时,容器会负责销毁一些 bean 实例以释放资源。这个方法是在 Spring 容器创建 bean 实例的过程中被调用的。

public void registerDisposableBean(String beanName, DisposableBean bean) {
		synchronized (this.disposableBeans) {
			this.disposableBeans.put(beanName, bean);
		}
	}

	private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

registerDisposableBean只是将我们的相应的销毁逻辑(DisposableBeanAdapter)封装到了一个集合中(有销毁逻辑的bean的集合)。至此我们的销毁方法的注册的全部流程就已经结束了,下面就可以开始分析在容器关闭的时候是怎么执行我们的这些销毁逻辑的。

3. Bean的销毁过程

前面已经分析了bean销毁逻辑的注册过程,而且前面说到容器关闭有两种方法,分别是注册JVM钩子和调用容器的close方法显示关闭,其实他们的底层都是调用了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);
			}

			if (!NativeDetector.inNativeImage()) {
				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.
			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.
			destroyBeans();

			// Close the state of this context itself.
			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);
		}
	}

上面代码关于bean销毁所调用的核心方法是destroyBeans

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

然后destroyBeans底层调用的是destroySingletons方法

	@Override
	public void destroySingletons() {
		super.destroySingletons();
		// 清空manualSingletonNames集合
		updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
		clearByTypeCache();
	}

继续进入super.destroySingletons方法

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

		String[] disposableBeanNames;
		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();
	}

有关执行前面的销毁逻辑的代码就是下面两句

//定义一个String数组
String[] disposableBeanNames;
//	private final Map<String, Object> disposableBeans = new LinkedHashMap<>();disposableBeans就是我们前面讲注册销毁逻辑时最后封装的那个集合
		synchronized (this.disposableBeans) {
		    //然后获得结合的keySet(也就是我们的beanname)
			disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
		}
		for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
		//遍历beanname,执行销毁逻辑
			destroySingleton(disposableBeanNames[i]);
		}

上面代码就是拿到了我们前面注册销毁逻辑的那个集合,然后遍历执行destroySingleton方法

public void destroySingleton(String beanName) {
		// Remove a registered singleton of the given name, if any.
		// 先从单例池中移除掉
		removeSingleton(beanName);
		// Destroy the corresponding DisposableBean instance.
		DisposableBean disposableBean;
		synchronized (this.disposableBeans) {
			disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
		}
		destroyBean(beanName, disposableBean);
	}

然后上面的方法首先将我们的bean从单例池中移除掉,然后将我们的bean同样从this.disposableBeans移除掉,最后执行destroyBean(beanName, disposableBean)

protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
		// dependentBeanMap表示某bean被哪些bean依赖了
		// 所以现在要销毁某个bean时,如果这个Bean还被其他Bean依赖了,那么也得销毁其他Bean
		// Trigger destruction of dependent beans first...
		Set<String> dependencies;
		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);
			}
			for (String dependentBeanName : dependencies) {
			//当前依赖我们这个bean的其他bean也要执行销毁逻辑(如果有销毁逻辑),这里是递归实现
				destroySingleton(dependentBeanName);
			}
		}
		//开始真正执行我们的销毁逻辑
		if (bean != null) {
			try {
				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);
	}

上面真正执行销毁逻辑的代码就是下面这段代码:

//开始真正执行我们的销毁逻辑
		if (bean != null) {
			try {
				bean.destroy();
			}
			catch (Throwable ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
				}
			}
		}

destory方法是DisposableBeanAdapter类的方法:

public DisposableBeanAdapter(
			Object bean, List<DestructionAwareBeanPostProcessor> postProcessors, AccessControlContext acc) {

		Assert.notNull(bean, "Disposable bean must not be null");
		this.bean = bean;
		this.beanName = bean.getClass().getName();
		this.invokeDisposableBean = (this.bean instanceof DisposableBean);
		this.nonPublicAccessAllowed = true;
		this.acc = acc;
		this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
	}

每个DisposableBeanAdapter对象,封装了对应的bean,以及容器中所有的DestructionAwareBeanPostProcessor(这就是销毁方法的逻辑)

public void destroy() {
//如果this.beanPostProcessors集合不为空,调用processor.postProcessBeforeDestruction方法
		if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
			for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
				processor.postProcessBeforeDestruction(this.bean, this.beanName);
			}
		}

		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);
				}
			}
		}

		if (this.destroyMethod != null) {
			invokeCustomDestroyMethod(this.destroyMethod);
		}
		else if (this.destroyMethodName != null) {
			Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
			if (methodToInvoke != null) {
				invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
			}
		}
	}

processor.postProcessBeforeDestruction(this.bean, this.beanName);这句代码底层就会根据我们前面判断某个bean有没有销毁逻辑的三种方法去执行我们bean的销毁逻辑的,至此某个bean底层执行我们制定的销毁逻辑的底层原理我们就分析完了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/268824.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloudAlibaba Seata在Openfeign跨节点环境出现全局事务Xid失效原因底层探究

原创/朱季谦 曾经在SpringCloudAlibaba的Seata分布式事务搭建过程中&#xff0c;跨节点通过openfeign调用不同服务时&#xff0c;发现全局事务XID在当前节点也就是TM处&#xff0c;是正常能通过RootContext.getXID()获取到分布式全局事务XID的&#xff0c;但在下游节点就出现获…

ros2+gazebo+urdf:ros2机器人使用gazebo的urdf文件中的<gazebo>部分官网资料

原文链接SDFormat extensions to URDF (the gazebo tag) — Documentation 注意了ros2的gazebo部分已经跟ros1的gazebo部分不一样了&#xff1a; Toggle navigation SpecificationAPIDocumentationDownload Back Edit Version: 1.6 Table of C…

我在代码随想录|写代码Day-Day之总结篇

我是用笔手写的我觉得这样可以对个人记忆会更好,而且理解更深解释也更清楚 下面是手写笔记 总结部分----- 第一章 二分 二分模版 图片可能反了下不过没有关系 图形打印模版题 第二章 链表 链表基本操作和疑问 链表代码操作和解析----5大操作 删除部分 对结点的操作 反了反了…

关于个人Git学习记录及相关

前言 可以看一下猴子都能懂的git入门&#xff0c;图文并茂不枯燥 猴子都能懂的git入门 学习东西还是建议尽可能的去看官方文档 权威且详细 官方文档 强烈建议看一下GitHub漫游指南及开源指北&#xff0c;可以对开源深入了解一下&#xff0c;打开新世界的大门&#xff01; …

若依SQL Server开发使用教程

1. sys_menu表中的将菜单ID修改为自动ID,解决不能增加菜单的问题&#xff0c;操作流程如下&#xff1a; 解决方案如下 菜单栏->工具->选项 点击设计器&#xff0c;去掉阻止保存要求更新创建表的更改选项&#xff0c;点确认既可以保存了 2 自动生成代码找不表的解决方案…

C语言--直接插入排序【排序算法|图文详解】

一.直接插入排序介绍&#x1f357; 直接插入排序又叫简单插入排序&#xff0c;是一种简单直观的排序算法&#xff0c;它通过构建有序序列&#xff0c;对于未排序的数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。 算法描述&#xff1a; 假设要排序…

idea 找不到 Free MyBatis plugin

idea 找不到 free mybatis plugin 可以使用mybatisX替换&#xff1a; 插件安装成功后&#xff0c;重启idea。

【English】水果单词小小汇总~~

废物研究生&#xff0c;只要不搞科研干啥都是开心的&#xff0c;啊啊啊啊啊科研要命。作为一个水果怪&#xff08;每天不吃水果就要命的那种哈哈哈哈&#xff09;突然发现竟然就知道什么apple、banana、orange&#xff01;惭愧惭愧&#xff0c;正好兴致正浓&#xff0c;来整理一…

Java HashMap在遍历时删除元素

文章目录 1. HashMap数据结构1.1 数组单向链表红黑树1.2 指定初始容量&#xff0c;省去多次扩容步骤1.3 获取map内容&#xff1a;Map.Entry 2. 遍历集合时删除元素3. computeIfAbsent()方法 1. HashMap数据结构 jdk是1.8版本 HashMap 线程不安全 ConcurrentHashMap 线程安全 1.…

jvm_下篇_补充_MAT从入门到精通

MAT从入门到精通 概述安装mac安装指定jdk配置内存 使用配置获取dump文件Overview下功能解释HistogramDominator TreeLeak SuspectsOverview功能说明结尾Thread_Overview OQLHeap Dump OverviewFind Object by address 概述 尽管JVM提供了自动内存管理的机制&#xff0c;试图降…

golang的jwt学习笔记

文章目录 初始化项目加密一步一步编写程序另一个参数--加密方式关于StandardClaims 解密解析出来的怎么用关于`MapClaims`上面使用结构体的全代码实战项目关于验证这个项目的前端初始化项目 自然第一步是暗转jwt-go的依赖啦 #go get github.com/golang-jwt/jwt/v5 go get githu…

小狐狸ChatGPT系统 H5前端底部菜单导航文字修改方法

小狐狸ChatGPT系统后端都前端都是编译过的&#xff0c;需要改动点什么非常难处理&#xff0c;开源版修改后也需要编译后才能使用&#xff0c;大部分会员也不会使用&#xff0c;像简单的修改下底部菜单文字、图标什么的可以对照处理。这里以小狐狸ChatGPT系统1.9.2版本H5端为例&…

Unity向量按照某一点进行旋转

Unity向量按照某一点进行旋转 一、unity的旋转二、向量按照原点进行旋转注意案例 三、向量按照指定位置进行旋转案例 一、unity的旋转 首先要知道一点就是在Unity的旋转中使用过四元数进行旋转的&#xff0c;如果对一个物体的rotation直接赋值你会发现结果不是你最终想要的结果…

Kubectl 部署有状态应用(上)

前面介绍了Deployment以及如何部署无状态应用。 Kubectl 部署无状态应用Deployment Controller详解&#xff08;上&#xff09;Deployment Controller详解&#xff08;下&#xff09; 本文将继续介绍如何在k8s上部署有状态应用。 有状态和无状态服务的区别 无状态&#xff…

数组元素反序

和前面的字符串逆向输出有异曲同工之妙 第一位和最后一位交换位置&#xff0c;然后用比大小循环 那么接下来修改一下这个程序&#xff0c;我们接下来解释一下p的概念 画图解释&#xff1a; 在最前面的 定义的时候&#xff0c;我们将p&#xff08;0&#xff09;定义在了1上&…

四、Spring IoC实践和应用(基于配置类方式管理 Bean)

本章概要 基于配置类方式管理 Bean 完全注解开发理解实验一&#xff1a;配置类和扫描注解实验二&#xff1a;Bean定义组件实验三&#xff1a;高级特性&#xff1a;Bean注解细节实验四&#xff1a;高级特性&#xff1a;Import扩展实验五&#xff1a;基于注解配置类方式整合三层…

抓包工具Fiddler的常用操作

文章目录 Fiddler概述Fiddler页面介绍常用功能介绍端口号的修改设置抓HTTPS数据Fillder过滤请求数据 接口相关Fiddler中查看请求信息Fiddler中查看响应信息 Fiddler模拟弱网测试Fiddler模拟mock数据Fillder篡改数据 Fiddler概述 fiddler是一款http协议调试代理工具&#xff0c;…

redis的那些事(二)——布隆过滤器

什么是布隆过滤器&#xff1f; 布隆过滤器&#xff08;Bloom Filter&#xff09;是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 布隆过滤器实现原理 布隆过滤器是一个bit向量或者说是一个b…

【linux提权】利用setuid进行简单提权

首先先来了解一下setuid漏洞&#xff1a; SUID (Set UID)是Linux中的一种特殊权限,其功能为用户运行某个程序时&#xff0c;如果该程序有SUID权限&#xff0c;那么程序运行为进程时&#xff0c;进程的属主不是发起者&#xff0c;而是程序文件所属的属主。但是SUID权限的设置只…

构建深度学习模型:原理与实践

构建深度学习模型&#xff1a;原理与实践 引言 随着人工智能技术的飞速发展&#xff0c;深度学习已经成为当今最为炙手可热的研究领域之一。深度学习通过模拟人脑神经网络的工作原理&#xff0c;使得计算机能够具备更强大的学习和识别能力。本文将深入探讨深度学习的基本原理…