请你谈谈:AnnotatedBeanDefinitionReader 显式地注册一个Bean到Spring容器,以及注册并解析配置类

为了深入探讨Spring框架中的beanDefinition对象,我们不可避免地要提及BeanFactoryPostProcessor这一核心类,它作为Spring的bean工厂后置处理器发挥着关键作用。接下来,我们将详细讨论BeanFactoryPostProcessor的执行时机,这是一个至关重要的环节,且Spring内部的处理机制相对复杂。本文旨在重点分析Spring如何确保这些执行时机得以严谨地遵循,并探讨如何扩展Spring的bean工厂后置处理器功能。
首先,通过一张图表,我们可以直观地理解Spring容器在启动过程中调用BeanFactoryPostProcessor后置处理器时的方法执行顺序。这将有助于我们更加清晰地把握Spring框架内部的工作流程和机制。
在这里插入图片描述

在这里插入图片描述
上述图示主要概述了Spring框架在调用BeanFactoryPostProcessor时的四个关键步骤(需要注意的是,这里仅聚焦于Spring如何触发BeanFactoryPostProcessor的调用,而并未涵盖Spring容器启动的全部流程)。
第一步,启动main方法,并在该方法中触发Spring容器的初始化。
第二步,调用AnnotationConfigApplicationContext的无参数构造函数。在这一步中,框架会首先实例化AnnotatedBeanDefinitionReader对象。这一步骤具有两个核心意义:

	public AnnotationConfigApplicationContext() {StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");this.reader = new AnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scanner = new ClassPathBeanDefinitionScanner(this);}

1.关于AnnotatedBeanDefinitionReader的用途(问题一)
2.实例化AnnotatedBeanDefinitionReader的过程(问题二)

接下来,Spring在②-2步骤中实例化了一个ClassPathBeanDefinitionScanner对象。这个对象通常用于执行Spring的类路径扫描功能,但值得注意的是,Spring在实际执行扫描操作时并未直接使用这个实例化的对象。相反,Spring在扫描的过程中会重新创建一个新的ClassPathBeanDefinitionScanner对象实例(我们暂且称之为b)。这里存在两个相同类型的对象(尽管它们都是ClassPathBeanDefinitionScanner的实例,但我们可以区分它们为a和b),这一设计有其特定的原因。为何需要两个ClassPathBeanDefinitionScanner对象实例(问题三)?至于问题三:如果Spring在内部扫描时未使用实例a,那么它为何会被创建?第②步完成了必要的准备和配置工作,为后续的扫描过程奠定了基础。

在步骤③中,register(Appconfig.class)方法被调用,它首先将Appconfig类解析为一个BeanDefinition对象。这一解析过程实际上是依赖于之前提到的AnnotatedBeanDefinitionReader对象,该对象负责将带有注解的类转化为Spring容器能够理解的BeanDefinition表示。随后,该BeanDefinition对象会被赋予一些默认的属性设置,并放置到BeanDefinitionMap中。

为何需要将BeanDefinition放入BeanDefinitionMap中呢?这主要是为了方便Spring容器后续的管理和检索。在Spring容器的生命周期中,它会遍历这个Map,并根据其中的BeanDefinition来实例化相应的Bean。对于Appconfig类而言,由于其包含多个带有@Bean注解的方法,这些方法的执行依赖于Appconfig实例本身,因此Appconfig的BeanDefinition必须存在于Map中,以确保它能够被实例化为一个Bean。关于Appconfig的实例化过程,它比一般的Bean实例化要复杂得多,因为它可能涉及到代理和CGLIB等技术的使用,这些将在后续的文章中详细解释。

至于为何Appconfig类是通过register(Appconfig.class)方法手动添加到Map中而不是通过扫描,这是因为Appconfig类自身无法被自己的扫描器所扫描到。在Spring中,一般的类是通过解析配置类(如Appconfig)上的@ComponentScan注解,然后由扫描器自动发现并添加到BeanDefinitionMap中的。但由于Appconfig是配置类本身,它无法扫描自己,因此需要通过手动调用的方式将其注册到容器中。

接下来是步骤④,其中包括了从④-1到④-4的一系列操作,而④-5则是本文重点讨论的,即执行Spring中的BeanFactoryPostProcessor。这个步骤是Spring容器启动过程中的关键一环,用于在Bean实例化之前对Bean的定义进行后处理

AnnotatedBeanDefinitionReader这个类的核心作用主要体现在以下两个方面:

  1. 编程式动态注册带注解的Bean:假设我们有一个位于com.shadow包下的类A,并且该类上标注了如@Component这样的注解。在标准配置下,Spring容器会通过扫描机制自动发现并注册此类。然而,在某些特定场景下,Spring可能无法扫描到com.shadow包,导致类A无法被容器实例化。这些特定场景包括但不限于:类A是动态生成的,在容器启动时尚不存在;或者com.shadow包下存在大量类,但仅有个别类(如类A)带有注解,此时通过扫描整个包来发现这些类显得效率低下。此时,我们可以利用AnnotatedBeanDefinitionReader的register(Class<?>clazz)方法,将类A显式地注册到Spring容器中。这个过程实际上是将类A解析为BeanDefinition对象,并将其添加到Spring的BeanDefinitionMap中,从而确保类A能够被容器正常实例化和管理。

为了验证这一功能,我们可以编写一个简单的示例,通过AnnotatedBeanDefinitionReader手动注册一个带有@Component注解的类,并观察其在Spring容器中的行为。
在这里插入图片描述
在这里插入图片描述

那么,除了能够动态显式注册一些Spring在扫描过程中可能遗漏的类之外,AnnotatedBeanDefinitionReader还有哪些功能呢?在初始化Spring容器的过程中,它究竟扮演了怎样的角色?或者说,如果没有需要动态显式注册的类,它是否就失去了存在的意义?此外,AnnotatedBeanDefinitionReader对象的应用场景仅限于注册自定义类吗?——答案是否定的。它还有一个重要应用场景,那就是注册我们的配置类。对于不太了解配置类的读者,可以简单理解为那些标注了@Configuration和@ComponentScan注解的类,例如常见的Appconfig.java。这类配置类通过AnnotatedBeanDefinitionReader注册到Spring容器中,起到了配置和管理Bean的作用。

@Configuration
@ComponentScan("com.springIoc.config")
public class AppConfig {
}

那么,为何配置类需要手动注册呢?这主要是因为配置类在Spring的自动扫描机制中具有一定的特殊性。在Spring框架中,配置类(如Appconfig.java)往往包含了@ComponentScan注解,该注解用于指定需要被扫描的包路径。然而,由于Spring的扫描过程需要依赖于配置类中的@ComponentScan注解来确定扫描范围,因此配置类本身在扫描开始之前就必须被Spring容器所知晓。

具体来说,当Spring启动并尝试进行自动扫描时,它首先需要解析配置类(如Appconfig.java)中的@ComponentScan注解,以获取需要扫描的包名。然后,Spring会根据这个包名去扫描该包下的所有Bean定义。由于配置类本身包含了这些关键信息,因此它必须在一开始就手动注册给Spring容器。

一旦Spring获得了配置类的Class对象(如Appconfig.class),它就会将其解析为一个BeanDefinition对象。这个BeanDefinition对象包含了配置类的所有元数据,包括@ComponentScan注解的值。之后,Spring就会根据这个BeanDefinition对象中的信息去扫描指定的包路径,从而发现和注册其他Bean。

因此,配置类需要手动注册的原因在于其包含了扫描过程中所需的关键信息,这些信息在扫描开始之前就必须被Spring容器所获取。

作用:

  1. 动态注册Bean:AnnotatedBeanDefinitionReader的主要功能之一是能够动态、明确地注册一个Bean到Spring容器中。这允许开发者在运行时根据需求灵活添加Bean定义。
  2. 类解析功能:除了注册功能外,它还具备解析类的能力。这种解析能力与Spring框架中用于扫描和解析类的机制相似,能够处理带有注解的类,并将其转换为Spring容器可识别的Bean定义。

应用场景:

  1. 程序员提供的Bean注册:在开发过程中,当程序员需要显式地注册一个Bean到Spring容器中时,可以使用AnnotatedBeanDefinitionReader。这种方式尤其适用于那些不在Spring的自动扫描路径下,或者需要特殊配置的Bean。
  2. 配置类的注册与解析:在初始化Spring容器的过程中,AnnotatedBeanDefinitionReader扮演着关键角色。它负责注册并解析配置类(如标注了@Configuration和@ComponentScan的类)。这些配置类通常包含了Bean的定义和扫描路径的配置,是Spring容器构建过程中不可或缺的部分。通过AnnotatedBeanDefinitionReader,这些配置类能够被正确地加载和解析,从而确保Spring容器能够按照预期的方式运行。

针对AnnotatedBeanDefinitionReader应用场景的第二点,关于其在Spring容器初始化过程中的应用,我将进一步详细阐述。通常,程序员在初始化Spring容器时,会采用多种不同的代码实现方式,但核心原理是相似的。以下,我将列举两种常见的示例来说明这一点。
第一种写法:

AnnotationConfigApplicationContext ac =new AnnotationConfigApplicationContext();
// 动态注册一个配置类
ac.register(Appconfig.class);
// 调用refresh方法
// 这里很多资料都叫做刷新spring容器,但是我觉得不合适,这是硬核翻译,比较生硬。笔者觉得理解为初始化spring容器更加精准,至于为什么以后慢慢更新再说
ac.refresh();

第二种写法:

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Appconfig.class);

实际上,虽然两种方法都能获取到AnnotationConfigApplicationContext(简称AC对象),但推荐第一种写法的原因在于其提供了更大的灵活性和控制力。首先,第二种方法是在Spring容器完成初始化后才获取AC对象,此时容器的配置和状态已经固定,限制了后续能进行的操作。而第一种方法允许在容器初始化之前获取AC对象,从而能够执行更多的定制化和配置操作。

具体来说,①在容器初始化之前,我们可以动态地注册自定义的Bean,这正是AnnotatedBeanDefinitionReader的应用场景之一。②此外,我们还可以利用AC对象来管理和控制Spring的循环依赖特性,这在某些复杂的应用场景中尤为关键。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp 微信小程序根据后端返回的文件链接打开并保存到手机文件夹中【支持doc、docx、txt、xlsx等类型的文件】!

项目场景&#xff1a; 我们在使用uniapp官方提供的uni.downloadFile以及uni.saveFile时&#xff0c;会发现这个文件下载的默认保存位置和我们预想的不太一样&#xff0c;容易找不到&#xff0c;而且没有提示&#xff0c;那么我们就需要把文件打开自己保存并且有提示保存到哪个…

网络安全保险产业发展洞察报告(2024)

数字经济高速增长&#xff0c;黑客攻击、数据泄露等网络安全风险可能直接导致企业遭受巨额的财务损失。网络安全保险作为风险转移和风险管理的有效工具&#xff0c;正逐渐成为数字安全框架中不可或缺的一环。 《网络安全保险产业发展洞察报告&#xff08;2024&#xff09;》梳…

百度“文心•跨模态大模型”又有新动态,支持内容分析时输出自定义标签库

大模型真正的价值在于应用。 一、基本概念 AI大模型具有强大的表征学习能力&#xff0c;能够在海量数据中提取有用的特征&#xff0c;为各种复杂任务提供解决方案。例如GPT-4o、BERT等模型的出现&#xff0c;不仅展示了大规模参数和复杂计算结构的优势&#xff0c;还在自然语…

STM32第二十课:FreeRTOS任务管理和信号量

目录 一、任务管理方式二、任务堆栈溢出检测三、二值信号量&#xff08;任务同步&#xff09;四、计数信号量五、互斥信号量六、队列 一、任务管理方式 1.任务创建成功后会添加到就绪链表中&#xff0c;开启调度器&#xff0c;此时任务调度器会去就绪链表中找优先级最高的任务执…

二叉树 —— OJ题目详解

1.二叉树的前序遍历 二叉树的前序遍历比较简单&#xff0c;但是在力扣上写这个接口需要注意几个点&#xff1a; int* preorderTraversal(struct TreeNode* root, int* returnSize) {} preorderTraversal 的返回值是动态开辟的数组&#xff0c;里面存放的是前序遍历的顺序int*…

【Linux取经之路】Linux常见指令

目录 基本指令 常见指令 1&#xff09;ls —— 对于目录&#xff0c;列出该目录下的所有子目录和文件&#xff1b;对于文件&#xff0c;将列出文件名及其他信息 2&#xff09;pwd —— 显示当前所在的目录 ​编辑 3&#xff09;cd —— 切换到指定路径下 4&#xff09;t…

itextpdf字体选择

itextpdf 版本7.2.5 itextpdf-html2pdf 版本4.0.5 这里讲的是通过html转pdf&#xff0c;在html2pdf中是通过html中font-family样式来确定字体的&#xff0c;那已知font-family的情况&#xff0c;怎么确定pdf中实际用的字体&#xff0c;大致分为两步&#xff1a; 1、通过font…

识别 TON 生态系统中前10种加密资产,以bitget 钱包为例

元描述&#xff1a;想要找到下一个 100 倍加密货币投资&#xff1f;请密切关注这篇文章&#xff1b;它揭示了所有可能很快变得非常有价值的 TON 网络宝石。 由 Telegram 提供支持的 TON&#xff08;开放网络&#xff09;生态系统正在蓬勃发展&#xff01;这是一个充满激动人心的…

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【25】【分布式事务】

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【25】【分布式事务】 本地事务事务的基本性质事务的隔离级别&#xff08;下面四个越往下&#xff0c;隔离级 别越高&#xff0c;并发能力越差&#xff09;事务的传播行为&#xff08;是否…

【Hive SQL 每日一题】找出各个商品销售额的中位数

文章目录 测试数据需求说明需求实现方法1 —— 升序计算法方法2 —— 正反排序法 补充 测试数据 -- 创建 orders 表 DROP TABLE IF EXISTS orders; CREATE TABLE orders (order_id INT,product_id INT,order_date STRING,amount DOUBLE );-- 插入 orders 数据 INSERT INTO ord…

软件工程课设——成绩管理系统

软件工程课设——成绩管理系统 该文档是软件工程课程设计&#xff0c;成绩管理子系统的开发模块仓库。 功能分析 从面向的用户分&#xff0c;成绩管理子系统主要面向三类用户&#xff0c;即至少需要满足这三类用户的需求&#xff1a; 学生&#xff1a;学生是成绩管理系统的…

深入理解 Git Reset 的三种模式及其使用场景

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Android ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 1. --soft 模式 2. --mixed 模式&#xff08;默认&#xff09; 3. --hard 模式 总结 结语 我的其他博客 前言 在日常的开发…

机器学习-1:人工智能、机器学习和深度学习的关系

人工智能&#xff08;AI&#xff09; 简单理解&#xff0c;任何一种事物只要具备了一定的智能就可以把它归类为人工智能。 官方定义&#xff1a;"AI is the field that sdudies the synthesis and analysis of computational agents that act intelligently." 其中&a…

安卓学习中遇到的问题【bug】

安卓学习中遇到的问题 1Gradle下载慢怎么办&#xff1f; Gradle下载慢怎么办&#xff1f; distributionUrlhttps://mirrors.cloud.tencent.com/gradle/gradle-7.5-bin.zip 2 Could not resolve all files for configuration ‘:classpath‘. &#xff1e; Could not resolv…

uniapp-vue3-vite 搭建小程序、H5 项目模板

uniapp-vue3-vite 搭建小程序、H5 项目模板 特色准备拉取默认UniApp模板安装依赖启动项目测试结果 配置自动化导入安装依赖在vite.config.js中配置 引入 prerttier eslint stylelint.editorconfig.prettierrc.cjs.eslintrc.cjs.stylelintrc.cjs 引入 husky lint-staged com…

处理在 electron 中使用开启了懒加载的 el-image 后,窗口最大化或窗口尺寸变化后图片无法显示的问题

文章目录 1、问题描述2、详情动图3、解决思路4、解决方案5、效果展示 1、问题描述 在 electron 中使用 el-image 时&#xff0c;开启了懒加载后&#xff0c;发现只有当窗口滚动后&#xff0c;图片才会显示&#xff0c;即便图片已经处于窗口的可视区域。当拖动窗口使其尺寸变大…

基于JAVA+SpringBoot+Vue+uniapp+协同过滤算法+爬虫+AI的减肥小程序

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 小程序用户登录&#…

前端开发体系+html文件详解

目录 html骨架 body主体内基本元素 基本元素 超文本&#xff08;超链接跳转&#xff09; 锚点 图片标签 列表标签 表格标签 框架标签&#xff08;窗口标签&#xff09; 音频标签 视频标签 VScode编译器 输入框 字体样式 实例展示&#xff1a; 首先简要介绍前端的整…

在VS2017下FFmpeg+SDL编写最简单的视频播放器

1.下载ShiftMediaProject/FFmpeg 2.下载SDL2 3.新建VC控制台应用 3.配置include和lib 4.把FFmpeg和SDL的dll 复制到工程Debug目录下&#xff0c;并设置调试命令 5.复制一下mp4视频到工程Debug目录下&#xff08;复制一份到*.vcxproj同一目录&#xff0c;用于调试&#xff09; 6…

python中的re模块--正则表达式

正则表达式&#xff0c;又称规则表达式。&#xff08;英语&#xff1a;Regular Expression&#xff0c;在代码中常简写为regex、regexp或RE&#xff09;&#xff0c;计算机科 学的一个概念。正则表达式通常被用来检索、替换那些符合某个模 式(规则)的文本 re模块作用 通过使用…