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

news2024/9/21 18:34:54

为了深入探讨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.coloradmin.cn/o/1927634.html

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

相关文章

顶顶通呼叫中心中间件-添加自定义变量到CDR方法(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-添加自定义变量到CDR方法(mod_cti基于FreeSWITCH) 1、自定义变量添加到cti.json 例&#xff1a;需要添加的变量为“bridge_uepoch" 2、添加进数据库 在数据库中找到表"cdr"在cdr表中也添加数据&#xff0c;数据名为新变量名&#xff1a…

基于Java的科大讯飞大模型API调用实现

写在前面&#xff1a;因为现在自己实习的公司新拓展的一个业务是结合AI的低代码平台&#xff0c;我负责后端的开发&#xff0c;之前一直都是直接使用gpt或者文心一言等ui界面来直接使用大模型&#xff0c;从来没有自己调接口过&#xff0c;所以本文记录一下自己第一次使用大模型…

P2p网络性能测度及监测系统模型

P2p网络性能测度及监测系统模型 网络IP性能参数 IP包传输时延时延变化误差率丢失率虚假率吞吐量可用性连接性测度单向延迟测度单向分组丢失测度往返延迟测度 OSI中的位置-> 网络层 用途 面相业务的网络分布式计算网络游戏IP软件电话流媒体分发多媒体通信 业务质量 通过…

从零开始做题:什么奇奇怪怪的东西

题目 解题 mrf拓展名&#xff0c;macro recorder打开&#xff0c;鼠标键盘的记录 然后解压flag.zip即可&#xff0c;发现有一个挂载的文件&#xff0c;直接打开后 显示所有的隐藏文件 一个一个打开 然后进行拼接运行吧估计。 首先打开txt文件直接久就给出了代码&#xff1…

maven项目容器化运行之2-maven中使用docker插件调用远程docker构建服务并在1Panel中运行

一.背景 公司主机管理小组的同事期望我们开发的maven项目能够在1Panel管理的docker容器部署。上一篇写了先开放1Panel中docker镜像构建能力maven项目容器化运行之1-基于1Panel软件将docker镜像构建能力分享给局域网-CSDN博客。这一篇就是演示maven工程的镜像构建、容器运行、运…

学习大数据DAY16 PLSQL基础语法5

目录 异常 自定义异常的格式 raise_application_error 处理异常 预定义异常 SQLcode和SQLerrm 非预定义异常 作业 触发器 触发器基本概念 DML触发器 DML触发器使用 instead of 触发器 管理触发器 作业2 函数、过程和包 函数 过程 参数 1. in 参数 2.out 参…

KALI使用MSF攻击安卓设备

这期是kali使用MSF进行安卓渗透的保姆级别教程&#xff0c;话不多说&#xff0c;直接开始。 准备材料&#xff1a; 1.装有kali的实体机或虚拟机&#xff08;这里用实体机进行演示&#xff09; 2.一台安卓10.0以下的手机 打开kali&#xff0c;先用ifconfig查看自己的kali IP地址…

MySQL第八次作业

一、备份与恢复作业&#xff1a; 创库,建表&#xff1a; CREATE DATABASE booksDB; use booksDB; CREATE TABLE books ( bk_id INT NOT NULL PRIMARY KEY, bk_title VARCHAR(50) NOT NULL, copyright YEAR NOT NULL ); CREATE TABLE authors …

Git提交了敏感信息,通过BFG工具撤回或修改很久之前已经提交的内容

Git 提交了敏感信息怎么办&#xff1f; 这篇文章的由来&#xff0c;由于自己在提交代码的时候不小心把服务器的ip地址&#xff0c;还有数据库的密码给push到github上面去了。那么问题来了&#xff0c;我这个已经是一个月之前的提交的呢&#xff0c;现在还能改吗&#xff1f;别…

SIM900发送中文短信的处理过程

SIM900发送中文短信的处理过程 1、短信中心号码处理: 短信中心号码可以使用ATCSCA?获取。 在获取之前&#xff0c;最好将设置使用GSM字符&#xff1a; ATCSCS"GSM" OK ATCSCA? CSCA: "8613800755500",145 OK 这样一来&#xff0c;我就得…

Python酷库之旅-第三方库Pandas(023)

目录 一、用法精讲 58、pandas.isnull函数 58-1、语法 58-2、参数 58-3、功能 58-4、返回值 58-5、说明 58-6、用法 58-6-1、数据准备 58-6-2、代码示例 58-6-3、结果输出 59、pandas.notna函数 59-1、语法 59-2、参数 59-3、功能 59-4、返回值 59-5、说明 5…

线程的复习

目录 大纲Java中的线程概念创建线程的方法线程的生命周期线程的同步和通信线程的优先级和调度线程的中断 案例 大纲 Java中的线程概念 在Java中&#xff0c;线程是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程之中&#xff0c;是进程中实际运作的部分。一个…

python单测框架之pytest常见用法

单测框架的作用 测试发现&#xff1a;从多个文件中寻找测试用例。测试执行&#xff1a;按照一定顺序去执行并且生成结果。测试断言&#xff1a;判断最终结果与实际结果的差异。测试报告&#xff1a;统计测试进度、耗时、通过率&#xff0c;生成测试报告。 pytest简介 pytest是…

51单片机10(蜂鸣器介绍)

一、蜂鸣器介绍&#xff1a; 1、蜂鸣器是一种一体化结构的电子讯响器&#xff0c;采用直流电压供电&#xff0c;广泛应用于电子产品中作为发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器。 &#xff08;1&#xff09;压电式蜂鸣器&#xff0c;它主要由多谐的一个增胀器…

Cyber Weekly #15

赛博新闻 1、OpenAI 绝密项目「草莓」首次曝光 据外媒路透社报道&#xff0c;OpenAI 内部正在一个代号为「草莓&#xff08;Strawberry&#xff09;」的项目中开发一种新的人工智能模型。该模型细节此前从未被报道过&#xff0c;而 OpenAI 正在努力证明该模型类型能够提供高级…

C++客户端Qt开发——信号和槽

三、信号和槽 1.信号和槽概述 在Qt中&#xff0c;用户和控件的每次交互过程称为一个事件。比如"用户点击按钮”是一个事件&#xff0c;"用户关闭窗口”也是一个事件。每个事件都会发出一个信号&#xff0c;例如用户点击按钮会发出"按钮被点击"的信号&…

ensp防火墙智能选举综合实验

实验要求&#xff1a; 实验图&#xff1a; 新增配置&#xff1a; 路由isp: 7&#xff1a; 保留ip操作&#xff1a; 一、DX区域&#xff1a; 1、源地址池配置&#xff1a; 2、nat策略&#xff1a; nat安全策略配置&#xff1a; 二、YD&#xff1a; 1、源地址池配置&#xf…

最值得推荐的10款Windows软件!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频播放量破百万https://aitools.jurilu.com/1.音乐播放器——Dopamine Dopamine是一款音乐播放器&#xff0c;设计简洁美观。它支持多种音频格式&#xff0c;包括wav、mp3、ogg…

平衡树——AcWing 253. 普通平衡树

平衡树 定义 平衡树是一种自平衡的二叉搜索树&#xff0c;它在进行插入和删除操作后能够自动调整其结构&#xff0c;以保持树的高度尽可能低&#xff0c;从而保证树的查找、插入和删除操作能够在对数时间内完成。最著名的平衡树有AVL树和红黑树。 AVL树&#xff1a;是一种严格…

10月23-25日|2024年武汉袋式除尘展重磅来袭

2024第六届&#xff08;武汉&#xff09;国际袋式除尘技术与设备展览会 时间&#xff1a;2024年10月23-25日 地点&#xff1a;武汉国际文化博览中心 展会介绍&#xff1a; 2024第6届&#xff08;武汉&#xff09;国际袋式除尘技术与设备展览会将于2024年10月23-25日在武汉文…