Spring源码:Bean生命周期(终章)
2023/5/23 18:52:06
本文主要是介绍Spring源码:Bean生命周期(终章),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
本系列前面讲解了Spring的bean定义、bean实例化、bean初始化等生命周期。这些步骤使我们能够了解bean从创建到准备好使用所经历的过程。但是,除了这些步骤,bean的销毁也是非常重要的一步。在本系列的最后,我们将深入探讨bean的销毁过程,包括在什么情况下会发生销毁、销毁的顺序以及如何在bean销毁之前执行一些清理任务等。通过学习bean的销毁过程,我们将更全面地了解Spring的bean生命周期。
在Spring中,有多种方式可以销毁bean。其中一种方式是在应用程序关闭时显式地调用applicationContext.close()
方法来关闭容器。这个方法将会销毁所有还没有被销毁的bean。
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); applicationContext.close();
实现DisposableBean接口
实现DisposableBean接口是一种销毁bean的简单方式。当bean容器关闭时,Spring会调用DisposableBean的destroy()方法来销毁bean。以下是一些示例代码:
import org.springframework.beans.factory.DisposableBean; @Component public class MyBean implements DisposableBean { @Override public void destroy() throws Exception { // 在这里清理资源 } }
使用@PreDestroy注解
使用@PreDestroy注解是另一种简单的方式来销毁bean。当bean容器关闭时,Spring会调用使用@PreDestroy注解的方法来销毁bean。以下是一些示例代码:
import javax.annotation.PreDestroy; @Component public class MyBean { @PreDestroy public void cleanUp() throws Exception { // 在这里清理资源 } }
registerDisposableBeanIfNecessary
registerDisposableBeanIfNecessary()
方法是一个非常重要的方法,它是在bean创建后进行处理bean销毁逻辑的前提。在Spring的AbstractBeanFactory
类中,该方法会检查当前bean是否实现了DisposableBean
接口或者@PreDestroy
注解,如果是的话,就会将该bean添加到一个DisposableBeanAdapter
对象中,该对象会在bean销毁时被调用以执行销毁任务。这个过程是在bean销毁之前执行的,以确保正确关闭应用程序。
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)); } } }
我大概讲下这个方法requiresDestruction
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) { return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors( bean, getBeanPostProcessorCache().destructionAware)))); }
- DisposableBeanAdapter.hasDestroyMethod:校验是否实现了DisposableBean或者AutoCloseable接口,如果没有的话,再查看是否bean定义的destroyMethodName属性是
(inferred)
,如果是的话,那么直接找这个类是否有close方法没有的话再找shutdown方法 - DisposableBeanAdapter.hasApplicableProcessors:是否有@PreDestroy注解
DisposableBeanAdapter
DisposableBeanAdapter
对象是一个适配器,用于在销毁bean时执行必要的处理。它会将DisposableBean
接口或@PreDestroy
注解的方法转换为一个回调方法,以便在bean销毁时执行。这种适配器模式允许非标准的bean销毁方法与Spring框架协同工作。
在将DisposableBeanAdapter
对象添加到一个DisposableBeanRegistry
对象中时,Spring会将该对象添加到一个bean销毁的注册表中。当需要销毁所有bean时,Spring就会从该注册表中获取所有需要销毁的bean,并按照正确的顺序执行销毁任务。这样就可以确保应用程序的正确关闭。
destroySingleton
当Spring程序关闭时,会调用destroyBeans
方法,这里我们分析关键部分代码:
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); }
- removeSingleton:先从单例池中移除掉
- this.disposableBeans.remove:这里返回的是我们之前调用registerDisposableBeanIfNecessary方法添加进去的DisposableBeanAdapter适配器
- destroyBean:直接销毁bean,这里注意一个小点就是如果当前bean被其他bean依赖了,那么先移除销毁其他Bean,然后就是调用适配器的destroy方法
总结
非常感谢您对 Spring 生命周期系列文章的关注和支持,我们在过去一个月中深入了解了 Spring 框架中 Bean 的生成、初始化、后置处理和销毁等过程,对于理解 Spring 框架的原理和机制非常有帮助。我们总结一下Spring到底做了那些事情将bean从生成到销毁的全过程:
- 项目启动时,ClassPathBeanDefinitionScanner扫描得到所有BeanDefinition,由于ACM技术所以此时beanclass属性为String类型的bean的名称
- 获取合并后的BeanDefinition
- beanClass开始真正的被加载替换原有String类型的bean的名称
- 调用实例化前处理方法applyBeanPostProcessorsBeforeInstantiation
- 通过构造方法创建Bean实例
- 后置处理合并后的BeanDefinition,调用postProcessMergedBeanDefinition(寻找注入点)
- 调用实例化后处理方法postProcessAfterInstantiation
- 开始进行属性注入:postProcessProperties
- 调用初始化前处理方法:applyBeanPostProcessorsBeforeInitialization
- 进行初始化:invokeInitMethods,会调用指定init方法或者afterPropertiesSet方法
- 调用初始化后处理方法:applyBeanPostProcessorsAfterInitialization(AOP)
- 容器关闭时,走bean的销毁逻辑,即今天所讲
这里面有很多逻辑流程我都在单独的文章中有细讲,比如FactoryBean、PropertyValues等等,由于是总结所以就不全写出来了,也希望大家可以好好理解Spring源码,下一步,我们将会着重讲解 Bean 的属性依赖注入。
这篇关于Spring源码:Bean生命周期(终章)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-27消息中间件底层原理资料详解
- 2024-11-27RocketMQ底层原理资料详解:新手入门教程
- 2024-11-27MQ底层原理资料详解:新手入门教程
- 2024-11-27MQ项目开发资料入门教程
- 2024-11-27RocketMQ源码资料详解:新手入门教程
- 2024-11-27本地多文件上传简易教程
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器