当前位置: 首页 > news >正文

Spring Boot 深入剖析:BootstrapRegistry 与 BeanDefinitionRegistry 的对比

在 Spring Boot 的启动过程中,BootstrapRegistry 和 BeanDefinitionRegistry 是两个名为“Registry”却扮演着截然不同角色的核心接口。理解它们的差异是深入掌握 Spring Boot 启动机制和进行高级定制开发的关键。

BootstrapRegistry 

	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);}

当我们查看SpringBoot的启动方法的源码,我们发现run方法的源码本质上是初始化了一个SpringApplication对象随后调用其run方法来执行。我们点击进去这个SpringApplication的构造方法中我们看到

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}

在SpringApplication这个构造方法初始化了两个类分别是BootstrapRegistryInitializer和ApplicationContextInitializer,这两个接口都是只有一个方法initialize,他们的作用则是分别对applicationContext和BootstrapRegistry来进行预处理,而BootstrapRegistry的作用则是体现在:当你需要创建一个 ApplicationContextInitializer 来定制应用上下文,但这个Initializer的逻辑依赖于一个特定的组件(例如,一个高级的 Decryptor 解密器用来解密数据库密码)。然而,这个 Decryptor 本身又可能依赖于Spring的环境配置(Environment),而 Environment 又是在ApplicationContext创建过程中才被完全初始化的。

这就形成了一个 启动阶段的循环依赖

  • 想创建 ApplicationContext → 需要先执行 ApplicationContextInitializer

  • 想执行 ApplicationContextInitializer → 需要先有 Decryptor 实例

  • 想创建 Decryptor 实例 → 又需要 Environment(它又来自于 ApplicationContext

BootstrapRegistry 的解决方案:
BootstrapRegistry 允许你在一切开始之前(在任何一个 ApplicationContextInitializer 执行之前),就通过 BootstrapRegistryInitializer 将像 Decryptor 这样的关键组件作为完全实例化的对象注册到一个临时的“工具箱”里。

因此BootstrapRegistry 是启动引导器,负责在最前期提供现成的工具实例。

BeanDefinitionRegistry 

对于BeanDefinitionRegistry 的实例化则是在BeanDefinitionRegistryPostProcessor的处理类当中的postProcessBeanDefinitionRegistry来对其进行实例化处理的。

  • 角色IoC 容器的建筑师

  • 定位:它是 Spring Framework 中 ApplicationContext 的核心接口,负责持有所有 Bean 的“蓝图”(BeanDefinition)。ApplicationContext 会根据这些蓝图来实例化、组装和管理所有的Bean。它是Spring IoC容器的心脏。它定义了应用程序中所有组件的基本信息,但并不负责实例化,而是为后续的实例化、依赖注入提供元数据。它是正式舞台的后台策划

也就是说当前容器内的bean所有信息都会放到BeanDefinitionRegistry 中来进行处理,BootstrapRegistry 的生命周期早于 BeanDefinitionRegistry。前者为后者的初始化过程提供支持,通常通过 ApplicationContextInitializer 将 BootstrapRegistry 中的实例“转移”或“注册”到 BeanDefinitionRegistry 中,使其成为被IoC容器管理的正式Bean

详细对比

维度BeanDefinitionRegistryBootstrapRegistry
所属阶段ApplicationContext 阶段 (主阶段)Bootstrap 阶段 (极早期)
核心目的注册Bean的定义信息 (BeanDefinition),即如何创建Bean的蓝图注册和持有完全实例化的对象实例,为引导过程提供现成的工具
注册内容BeanDefinition 对象(包含类名、作用域、属性值、初始化方法等元数据)。任何类型的对象实例 (如 RestTemplateDecryptor)。通过 Supplier 或 BootstrapRegistry.InstanceSupplier 延迟提供。
生命周期持久。与 ApplicationContext 同生命周期,伴随整个应用运行。短暂。仅在 Bootstrap 阶段有效。一旦 ApplicationContext 准备就绪,其使命基本完成,内容可被转移到正式容器中。
接口方法registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
removeBeanDefinition(String beanName)
getBeanDefinition(String beanName)
register(Class<T> type, BootstrapRegistry.InstanceSupplier<T> instanceSupplier)
register(Class<T> type, Supplier<T> supplier)
isRegistered(Class<T> type)
依赖解决解决 Bean之间的循环依赖(通过三级缓存机制)。解决 启动流程上的依赖问题(通过提前实例化关键对象,打破初始化顺序的僵局)。
获取方式通过 ApplicationContext (即 BeanFactory) 的 getBean() 方法获取最终Bean实例在 ApplicationContextInitializer 中,通过 BootstrapContext 的 get(Class<T> type) 方法获取预先注册的实例
典型应用注册所有由 @Component@Bean@Service 等注解定义的组件。Spring Cloud Config:在获取远端配置前注册安全的 RestTemplate
自定义引导:提前注册解密器、自定义的 PropertySourceLoader 等。
设计模式工厂模式:存储的是产品的设计图,需要时再根据图纸生产。仓库模式:直接存储了准备好的产品,需要时直接取用。

BootstrapRegistry 和 BeanDefinitionRegistry 是 Spring Boot 为解耦复杂的启动过程、清晰划分职责而设计的两个互补的组件。它们并非竞争或替代关系,而是分别在不同的生命周期阶段、为解决不同层面的问题而协同工作的伙伴。


文章转载自:

http://ajuoh458.ppfxg.cn
http://0F2gfFuy.ppfxg.cn
http://X7wB1byh.ppfxg.cn
http://C6EGgYeU.ppfxg.cn
http://KDWIDcXY.ppfxg.cn
http://vZKc0ze8.ppfxg.cn
http://uGT3plUk.ppfxg.cn
http://EyRriHeU.ppfxg.cn
http://2iZi88OK.ppfxg.cn
http://vp15euDn.ppfxg.cn
http://ATUp4HjG.ppfxg.cn
http://mgzkktBI.ppfxg.cn
http://PuKq7FOo.ppfxg.cn
http://pCqZ3uhQ.ppfxg.cn
http://2QteKmTg.ppfxg.cn
http://YpUlOzce.ppfxg.cn
http://Tqe1V2HC.ppfxg.cn
http://LvsfP0aD.ppfxg.cn
http://s7grJIDf.ppfxg.cn
http://BtkIY7Rc.ppfxg.cn
http://i69TKLfC.ppfxg.cn
http://AwPf6dwv.ppfxg.cn
http://eqfwu4U0.ppfxg.cn
http://F9FzlSPF.ppfxg.cn
http://SPcQzjUG.ppfxg.cn
http://ifnF1FGL.ppfxg.cn
http://lp3u0OFf.ppfxg.cn
http://cQiPK13N.ppfxg.cn
http://T1wWrBfT.ppfxg.cn
http://YDDCozQt.ppfxg.cn
http://www.dtcms.com/a/376263.html

相关文章:

  • [rStar] 解决方案节点 | `BaseNode` | `MCTSNode`
  • 鸿蒙:@Builder 和 @BuilderParam正确使用方法
  • 美图云修-一站式AI修图软件
  • 从齿轮到智能:机器人如何重塑我们的世界【科普类】
  • F12中返回的id里preview和response内容不一致的问题
  • 【CSS 3D 交互】实现精美翻牌效果:从原理到实战
  • vue二次封装ant-design-vue的table,识别columns中的自定义插槽
  • vue方法汇总
  • GPU硬件架构和配置的理解
  • C++类和对象初识
  • 笔记:乐鑫 (Espressif) 的生态策略与开发者悖论
  • SELinux策略:域转换与类型继承
  • 【VLMs篇】06:Cosmos-Reason1:从物理常识到具身推理
  • 图漾相机 FM851-E2 相关资料
  • 资产管理什么软件好
  • npm 安装命令中关于 @ 的讲解,如:npm install @vue-office/docx vue-demi
  • PowerBI 没实现的的联动同步下钻,QuickBI 实现了
  • k8s+jenkins+harbor构建Devops平台
  • 【中文教材】35. 证券市场指数
  • 36.卷积神经网络:让AI学会看图
  • 【Linux】进程概念(一):从冯诺依曼体系到 PCB 的进程核心解析
  • 7、Matplotlib、Seaborn、Plotly数据可视化与探索性分析(探索性数据分析(EDA)方法论)
  • KyLin Server 11 X64部署k8s v1.34.0
  • 【Redis】双写一致性及数据持久化
  • UE5全场景应用与核心优势解析 , 川翔云电脑渲染支持
  • 用deepseek对GPU服务器进行压力测试
  • day27|前端框架学习
  • YOLOv8 Linux 部署指南(GPU CPU 完整版)
  • 服务器都是用的iis, 前端部署后报跨域,不是用同一个服务器 是前端项目的服务器做Nginx转发,还是后端项目的服务器做Nginx转发?
  • 43.shell脚本循环与函数