Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象做准备,所以我们先明白Spring到底是怎么去创建Bean的,也就是先弄明白Bean的生命周期。
Bean的生命周期就是指:在Spring中,一个Bean是如何生成的,如何销毁的?
Bean的生成过程
1. 生成BeanDefinition
Spring启动的时候会进行扫描,会先调用
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
拿到所指定的包路径下的所有文件资源(******.class文件)
然后会遍历每个Resource,为每个Resource生成一个MetadataReader对象,这个对象拥有三个功能:
- 获取对应的Resource资源
- 获取Resource对应的class的元数据信息,包括类的名字、是不是接口、是不是一个注解、是不是抽象类、有没有父类,父类的名字,所实现的所有接口的名字,内部类的类名等等。
- 获取Resource对应的class上的注解信息,当前类上有哪些注解,当前类中有哪些方法上有注解
在生成MetadataReader对象时,会利用ASM技术解析class文件,得到类的元数据集信息合注解信息,在这个过程中也会利用ClassLoader去加载注解类(ClassUtils.getDefaultClassLoader()所获得的类加载器),但是不会加载本类。
有了MetadataReader对象,就相当于有了当前类的所有信息,但是当前类并没有加载,也是可以理解的,真正在用到这个类的时候才加载。
然后利用MetadataReader对象生成一个ScannedGenericBeanDefinition对象,注意此时的BeanDefinition对象中的beanClass属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object,它即可以存储类的名字,也可以存储class对象)
2. 合并BeanDefinition
如果某个BeanDefinition存在父BeanDefinition,那么则要进行合并
3. 加载类
有了BeanDefinition之后,后续就会基于BeanDefinition去创建Bean,而创建Bean就必须实例化对象,而实例化就必须先加载当前BeanDefinition所对应的class,在AbstractAutowireCapableBeanFactory类的createBean()方法中,一开始就会调用:
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
这行代码就是去加载类,该方法是这么实现的:
if (mbd.hasBeanClass()) { return mbd.getBeanClass(); } if (System.getSecurityManager() != null) { return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext()); } else { return doResolveBeanClass(mbd, typesToMatch); }
public boolean hasBeanClass() { return (this.beanClass instanceof Class); }
如果beanClass属性的类型是Class,那么就直接返回,如果不是,则会根据类名进行加载(doResolveBeanClass方法所做的事情)
会利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用ClassUtils.getDefaultClassLoader()所返回的类加载器来加载。
ClassUtils.getDefaultClassLoader()
- 优先获取当前线程中的ClassLoader
- 如果为空,则获取加载ClassUtils类的类加载器(正常情况下,就是AppClassLoader,但是如果是在Tomcat中运行,那么则会是Tomcat中为每个应用所创建的WebappClassLoader)
- 如果为空,那么则是bootstrap类加载器加载的ClassUtils类,那则获取系统类加载器进行加载
4. 实例化前
允许第三方可以不按照Spring的正常流程来创建一个Bean,可以利用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法来提前返回一个Bean对象,直接结束Bean的生命周期
5. 推断构造方法
单独讲
6. 实例化
构造方法反射得到一个实例
7. BeanDefinition的后置处理
for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof MergedBeanDefinitionPostProcessor) { MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp; bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName); } }
这里可以处理BeanDefinition,但是此时实例对象已经生成好了,所以修改beanClass已经没用了,但是可以修改PropertyValues,比如:
public class LubanMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor { public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { if (beanName.equals("userService")) { beanDefinition.setBeanClass(User.class); // 没用 beanDefinition.getPropertyValues().add("name","xxx"); } } }
8. 填充属性
单独讲
9. 执行Aware
- ((BeanNameAware) bean).setBeanName(beanName);
- ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
- ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
10. 初始化前
for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; }
11. 初始化
- ((InitializingBean) bean).afterPropertiesSet();
- 执行BeanDefinition中指定的初始化方法
12. 初始化后
for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; }
Bean的销毁过程
1. 容器关闭
2. 发布ContextClosedEvent事件
3. 调用LifecycleProcessor的onClose方法
4. 销毁单例Bean
- 找出所有DisposableBean(实现了DisposableBean接口的Bean)
- 遍历每个DisposableBean
- 找出依赖了当前DisposableBean的其他Bean,将这些Bean从单例池中移除掉
- 调用DisposableBean的destroy()方法
- 找到当前DisposableBean所包含的inner beans,将这些Bean从单例池中移除掉 (inner bean参考https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-inner-beans)
这里涉及到一个设计模式:适配器模式
在销毁时,Spring会找出实现了DisposableBean接口的Bean。
但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属于“DisposableBean”,这些Bean在容器关闭时都要调用相应的销毁方法。
所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
会把实现了AutoCloseable接口的类封装成DisposableBeanAdapter,而DisposableBeanAdapter实现了DisposableBean接口。
相关推荐
AIGC_基于ControlNet的AI视频生成算法_支持动漫+写实风格转换_附项目源码+流程教程_优质项目实战
app开发
毕业设计指南-word
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
信息收集思维导图
内容概要:本文详细介绍了三维偏微分方程组的数值解法及其一阶近似的推导过程。首先,针对定义在一个三维立方体域上的六个耦合偏微分方程组,选择了有限差分法(FDM)作为数值求解的方法。文中提供了详细的离散化步骤、边界条件设定以及迭代求解的具体实现,并附带了完整的Python代码用于求解和可视化结果。其次,通过对六个方程的线性组合,推导出了一阶近似方程,证明了在特定条件下,系统的演化可以由一个扩散方程来描述。最后,对不同参数σ下的数值结果进行了分析,展示了不同σ值对解的影响。 适合人群:具备数学建模和编程基础的研究人员和技术爱好者,尤其是对偏微分方程数值解感兴趣的学者。 使用场景及目标:适用于需要解决复杂物理现象模拟的问题,如流体力学、热传导等领域。通过学习本文,读者能够掌握有限差分法的基本思想和应用技巧,同时理解如何利用Python进行科学计算和数据可视化。 其他说明:本文不仅提供理论推导,还给出了具体的代码实现,便于读者理解和复现实验结果。此外,文中涉及的可视化部分可以帮助直观地展示数值解的特点和变化趋势。
大数据项目深度研究分析报告.docx
对于WIN11系统连接共享打印机出现提示:windows无法连接到打印机,请检查 打印机名并重试,以及“操作无法完成(错误 0x00000709)”等提示进行解决。
内容概要:本文详细介绍了Docker的重要概念、常用指令及其应用场景,旨在帮助初学者快速掌握Docker的使用方法。主要内容涵盖镜像和容器的概念区分、镜像的获取方式(网络拉取、本地加载)、镜像的使用(查看、创建容器、删除)、容器的管理(进入、退出、停止、删除)、镜像的生成(自动构建、手动提交)以及镜像的分享(在线存储库、本地导出)。此外,还涉及了无用数据的清理和一些常用的可视化管理工具。 适合人群:对Docker感兴趣的初学者,尤其是希望快速上手并应用于实际项目的开发人员。 使用场景及目标:适用于需要快速搭建一致运行环境、进行应用部署和维护的技术团队。通过学习本文,读者能够独立完成Docker环境的搭建、镜像和容器的管理,从而提高开发效率和环境一致性。 其他说明:文中提供了丰富的实例和官方文档链接,便于读者深入理解和实践。同时,附带了一些实用的参考资料,方便进一步探索Docker的高级特性。
矢量边界,行政区域边界,精确到乡镇街道,可直接导入arcgis使用
内容概要:本文详细介绍了动态综合评价中的无量纲化方法,并提供了Python代码实现。主要内容包括:数据准备、静态无量纲化方法(极差法、Z-score标准化、均值法)、三种动态无量纲化改进方法(标准序列法、全序列法、增量权法)。文中还进行了结果分析与比较,得出了全序列法是最推荐的方法,因其能够同时保留横向和纵向信息。最后,文章展示了如何将这些方法应用于TOPSIS综合评价系统,以及如何通过熵权法计算权重。 适合人群:具备一定数据分析和编程基础的研究人员、数据科学家、工程师。 使用场景及目标:适用于需要对多维时序数据进行无量纲化处理和综合评价的场景,如生产质量监控、供应商评估等。目标是帮助用户理解和实现动态综合评价中的无量纲化方法,提高数据处理和分析能力。 其他说明:本文不仅提供了详细的代码实现,还通过实例验证了不同方法的效果,确保读者能够深入理解每种方法的特点和应用场景。
腾讯AI封装调用
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
内容概要:本文详细介绍了A*算法的传统框架及其在路径规划中的局限性,并提出了多项改进措施。首先,针对启发函数进行了优化,引入了基于机器学习的预测方法以及动态权重调整,使得路径更加智能化和平滑化。其次,在邻接表和优先队列方面采用了更高效的数据结构,提高了算法的执行效率。实验结果显示,改进后的A*算法不仅缩短了路径长度,还显著降低了运行时间和空间开销。此外,作者对比了多种常见路径规划算法(如Dijkstra、RRT),展示了改进A*算法在不同场景下的优越性能。 适合人群:从事机器人导航、自动驾驶、游戏开发等领域研究的技术人员,尤其是对路径规划算法有一定了解并希望深入探索优化方法的研究者。 使用场景及目标:①需要在二维或三维环境中进行高效路径规划的应用场合;②希望通过优化现有算法来提升系统性能的研发团队;③希望掌握更多关于路径规划理论和技术细节的学习者。 其他说明:文中提供了具体的MATLAB代码片段用于解释各个部分的具体实现方式,并分享了一些实用技巧,如优先队列的容器映射实现和动画绘制优化等。
app开发
网络工程师(中级)是软考(计算机技术与软件专业技术资格考试)的一部分,主要考察计算机网络基础、网络安全、网络管理、操作系统、数据库等内容,考试分为上午的基础知识选择题和下午的案例分析题。
IoT最新进展
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
前端开发_VueCli3_H5模板_集成高德地图MintUI_1742856847.zip