【Spring Boot 源码学习】BootstrapRegistry 详解

《Spring Boot 源码学习系列》

在这里插入图片描述

BootstrapRegistry 详解

  • 一、引言
  • 二、往期内容
  • 三、主要内容
    • 3.1 源码初识
    • 3.2 register 方法
    • 3.3 registerIfAbsent 方法
    • 3.4 isRegistered 方法
    • 3.5 getRegisteredInstanceSupplier 方法
    • 3.6 addCloseListener 方法
    • 3.7 InstanceSupplier 内部接口类
      • 3.7.1 get 方法
      • 3.7.2 getScope 默认方法
      • 3.7.3 withScope 默认方法
      • 3.7.4 of 静态方法
      • 3.7.5 from 静态方法
    • 3.8 Scope 内部枚举类
  • 四、总结

一、引言

前面的博文《BootstrapRegistryInitializer 详解》,Huazie 带大家一起详细分析了 Spring Boot 启动时加载并初始化 BootstrapRegistryInitializer 及其相关的类的逻辑。其中有个 BootstrapRegistry 接口只是简单提及,本篇就详细分析一下 BootstrapRegistry 接口,这对于我们后续理解 《BootstrapRegistry 初始化器实现》的内容至关重要。

在这里插入图片描述

二、往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)
【Spring Boot 源码学习】深入 FilteringSpringBootCondition
【Spring Boot 源码学习】OnClassCondition 详解
【Spring Boot 源码学习】OnBeanCondition 详解
【Spring Boot 源码学习】OnWebApplicationCondition 详解
【Spring Boot 源码学习】@Conditional 条件注解
【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解
【Spring Boot 源码学习】RedisAutoConfiguration 详解
【Spring Boot 源码学习】JedisConnectionConfiguration 详解
【Spring Boot 源码学习】初识 SpringApplication
【Spring Boot 源码学习】Banner 信息打印流程
【Spring Boot 源码学习】自定义 Banner 信息打印
【Spring Boot 源码学习】BootstrapRegistryInitializer 详解
【Spring Boot 源码学习】ApplicationContextInitializer 详解
【Spring Boot 源码学习】ApplicationListener 详解
【Spring Boot 源码学习】SpringApplication 的定制化介绍

三、主要内容

注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。

在 《BootstrapRegistryInitializer 详解》 的 3.1 小节,我们对 BootstrapRegistry 进行了初步的介绍:它是一个用于存储和共享对象的注册表,这些对象在 ApplicationContext 准备好之前就可能已经被创建并需要被共享。

3.1 源码初识

首先让我们来看看 BootstrapRegistry 的源码:

public interface BootstrapRegistry {<T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier);<T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier);<T> boolean isRegistered(Class<T> type);<T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type);void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener);@FunctionalInterfaceinterface InstanceSupplier<T> {T get(BootstrapContext context);default Scope getScope() {return Scope.SINGLETON;}default InstanceSupplier<T> withScope(Scope scope) {// 。。。}static <T> InstanceSupplier<T> of(T instance) {return (registry) -> instance;}static <T> InstanceSupplier<T> from(Supplier<T> supplier) {return (registry) -> (supplier != null) ? supplier.get() : null;}}enum Scope {SINGLETON,PROTOTYPE}}

它包含了 5 个方法,1个内部接口类,1个内部枚举类,下面我们一一来介绍下:

3.2 register 方法

register 方法,包含两个参数:

  • Class<T> type :实例类型
  • InstanceSupplier<T> instanceSupplier :实例供应者

该方法用于将特定类型注册到注册表中。如果指定的类型已经被注册,并且尚未作为单例获取,那么它将被替换。

3.3 registerIfAbsent 方法

registerIfAbsent 方法,包含两个参数:

  • Class<T> type :实例类型
  • InstanceSupplier<T> instanceSupplier :实例供应者

如果尚未存在特定类型的注册,则向注册表中注册该类型。

3.4 isRegistered 方法

isRegistered 方法,只有一个参数:

  • Class<T> type :实例类型

该方法用于返回给定类型是否已注册。如果给定类型已经注册,则返回 true,否则,返回 false

3.5 getRegisteredInstanceSupplier 方法

getRegisteredInstanceSupplier 方法,也只有一个参数:

  • Class<T> type :实例类型

该方法返回给定类型的任何现有的 BootstrapRegistry.InstanceSupplier

3.6 addCloseListener 方法

addCloseListener 方法,只有一个参数:

  • ApplicationListener<BootstrapContextClosedEvent> listener :待添加的监听器

该方法用于添加一个 ApplicationListener,当 BootstrapContext 关闭并且 ApplicationContext 已经准备就绪时,该监听器将与 BootstrapContextClosedEvent 一起被调用。

3.7 InstanceSupplier 内部接口类

InstanceSupplier 内部接口类是用于提供实际实例的供应者。

它定义了一个 1 个普通方法,2 个默认方法,2 个静态方法。

知识拓展:
Java 8 开始,支持在接口中定义默认方法和静态方法。

  • 默认方法(Default Method)允许你在接口中添加一个有默认实现的非抽象方法。这使得接口可以更加灵活地扩展,而不需要破坏与现有代码的兼容性。默认方法使用关键字 default 进行声明,并提供了具体的实现。
  • 静态方法(Static Method)允许你在接口中定义一个静态方法,该方法可以在不创建接口实例的情况下调用。静态方法使用关键字 static 进行声明,并可以直接通过接口名来调用。

3.7.1 get 方法

get 方法,只包含一个参数:

  • BootstrapContext context :BootstrapContext 是一个用于获取其他引导实例的上下文

该方法是工厂方法,用于在需要时创建实例,后续我们在讲解 DefaultBootstrapContext 时也会涉及。

3.7.2 getScope 默认方法

getScope 默认方法,用于返回提供的实例的作用域;如果该方法没有被重写,则默认返回 Scope.SINGLETON

3.7.3 withScope 默认方法

default InstanceSupplier<T> withScope(Scope scope) {Assert.notNull(scope, "Scope must not be null");InstanceSupplier<T> parent = this;return new InstanceSupplier<T>() {@Overridepublic T get(BootstrapContext context) {return parent.get(context);}@Overridepublic Scope getScope() {return scope;}};
}

通过阅读上述代码可知,该方法根据其参数 scope ,返回一个指定作用域的新的 BootstrapRegistry.InstanceSupplier 的匿名对象,该匿名对象重写了 getgetScope 方法。这里使用匿名对象的好处就是可以在不定义新类的情况下快速地创建一个具有特定行为的对象。

细心的读者们,可能发现了匿名对象的 get 方法中,使用了 withScope 方法中定义的变量 parent,它被用来存储当前对象的引用 this

那么这里的 parent ,能不能直接替换成 this 呢?

显然是不可以的,this 关键字用在匿名内部类中,指代的是该匿名内部类本身,而不是外部对象。而匿名对象这里的重写的 get 方法,实际上需要调用 withScope 方法所在的对象的 get 方法来实现功能。如果这里用 this,实际上就是自己调自己,一直无限递归调用,最终导致栈溢出错误。

3.7.4 of 静态方法

该静态方法是一个工厂方法,用于为给定实例创建一个BootstrapRegistry.InstanceSupplier

return (registry) -> instance;

这里采用了 Java 8Lambda 表达式,也相当于如下的写法:

return new InstanceSupplier<T>() {@Overridepublic T get(BootstrapContext registry) {return instance;}
};

3.7.5 from 静态方法

该静态方法也是一个工厂方法,用于通过一个 Supplier 创建BootstrapRegistry.InstanceSupplier

return (registry) -> (supplier != null) ? supplier.get() : null;

这里也是用了 Java 8Lambda 表达式,相当于如下的写法:

return new InstanceSupplier<T>() {@Overridepublic T get(BootstrapContext registry) {return (supplier != null) ? supplier.get() : null;}
};

知识点:SupplierJava 8 开始引入,作为 java.util.function 包的一部分,它与 Lambda 表达式一起被引入,以支持函数式编程范式。该接口是为了简化无参数方法的表示,特别是在需要延迟执行或创建对象时。Supplier 接口只有一个抽象方法 get(),它不接受任何参数,但返回一个通用类型的值。

3.8 Scope 内部枚举类

Scope 表示一个实例的作用域,它只包含两个枚举变量,分别是:

  • SINGLETON :单例实例。InstanceSupplier 只会被调用一次,并且每次调用都会返回相同的实例。
  • PROTOTYPE :原型实例。InstanceSupplier 将在需要实例时被调用。

四、总结

本篇 Huazie 带大家通读了 BootstrapRegistry 的相关源码,这些内容对于后面的源码学习至关重要。

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

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

相关文章

故障诊断 | 一文解决,GRU门控循环单元故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍模型描述源码设计参考资料效果一览 文章概述 故障诊断 | 一文解决,GRU门控循环单元故障诊断(Matlab) 专栏介绍 订阅【故障诊断】专栏,不定期更新机器学习和深度学习在故障诊断中的应用;订阅

基于spring boot实现邮箱发送和邮箱验证

目录 一、邮箱发送实现1. 开通邮箱服务2. 添加邮箱依赖3.添加配置4.添加邮箱通用类5. 测试类 二、邮箱验证实现1.添加依赖2. 添加配置3.添加controller4. 测试 项目地址: https://gitee.com/nssnail/springboot-email 一、邮箱发送实现 1. 开通邮箱服务 使用qq邮箱、163邮箱都…

1月无代码资讯 | 两项低代码无代码行业报告相继重磅发布;GitHub Copilot Chat全面开放使用

栏目导读&#xff1a;无代码资讯栏目从全球视角出发&#xff0c;带您了解无代码相关最新资讯。 TOP3 大事件 1、ResearchAndMarkets.com "低代码无代码开发平台市场—— 2018-2028 年全球行业规模、份额、趋势、机遇及预测"报告发布 据雅虎财经近日资讯显示&#xf…

网络层 IP协议(1)

前置知识 主机:配有IP地址,但是不进行路由控制的设备 路由器:既配置了IP地址,又能进行路由控制的设备 节点:主机和路由器的总称 IP协议主要完成的任务就是 地址管理和路由选择 地址管理:使用一套地址体系,将网络设备的地址描述出来 路由选择:一个数据报如何从源地址到目的地址 …

【LVGL源码移植】

LVGL源码移植 ■ LVGL源码移植一&#xff1a;下载LVGL源码二&#xff1a;修改LVGL文件夹1: 将这5个文件&#xff0c;复制到一个新的文件夹2: 简化文件&#xff0c;减少内存消耗&#xff08;去除不必要的文件&#xff09;3: 为了规范化&#xff0c;我们将下列文件进行重命名 三&…

git使用方法(简易版)

一、git使用过程 1.注册git账号&#xff0c;并新建一个仓库&#xff1b; http://t.csdnimg.cn/ePcsx可以参考链接 2.在电脑文件夹中&#xff0c;右键选择 Git Bash Here,输入git init&#xff08;初始化仓库&#xff09;&#xff1b; git init - 初始化仓库。 Git 使用 git …

张维迎《博弈与社会》多重均衡与制度和文化(1)多重均衡问题

什么是多重均衡 我曾经在课堂上做过这样一个实验&#xff1a;随机选择男女两位同学参加一个选数字的游戏。游戏的基本规则为&#xff1a;每一个同学随机地从1到10十个数字中任意选择5个。如果两人选择的数字没有任何重复的话&#xff0c;则每人可以得到50元&#xff1b;如果两人…

Google Gemini Pro 国内版

Google Gemini Pro 国内版&#xff1a;【直达链接】 Google Gemini Pro 国内版 能力分类基准测试描述更高分数更好Gemini UltraGPT-4通用MMLU57个主题&#xff08;包括STEM、人文等&#xff09;的问题表示是90.0%86.4%&#xff08;5-shot, 报告&#xff09;推理Big-Bench Hard…

微信小程序(二十九)交互提示-界面加载框和提示框

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.showLoading加载框示范 2.showToast提示框示范 源码&#xff1a; index.wxml <!-- 列表渲染基础写法&#xff0c;不明白的看上一篇 --> <view class"students"><view class"it…

音视频数字化(音乐CD)

上篇文章【音视频数字化(音频数字化)】我们聊了音频数字化原理,其中谈到了音乐CD,结尾也提到了一个小问题:“CD音质是最高吗?为什么?”不知道大家是怎么理解的。 其实CD质量只是“无损”存储,但是数字化标准只是“44.1kHz,16bit”,因此相对于现在,音质不能说最高。 …

故障诊断 | 一文解决,BP神经网络的故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍模型描述源码设计参考资料效果一览 文章概述 故障诊断 | 一文解决,BP神经网络的故障诊断(Matlab) 专栏介绍 订阅【故障诊断】专栏,不定期更新机器学习和深度学习在故障诊断中的应用;订阅

解决:IDEA无法下载源码,Cannot download sources, sources not found for: xxxx

原因 Maven版本太高&#xff0c;遇到http协议的镜像网站会阻塞&#xff0c;要改为使用https协议的镜像网站 解决方案 1.打开设置 2. 拿到settings.xml路径 3. 将步骤2里箭头2的User settings file&#xff1a;settings.xml打开&#xff0c;作以下修改 保存即可。如果还不行…

15. 三数之和(力扣LeetCode)

文章目录 15. 三数之和题目描述双指针去重逻辑的思考a的去重b与c的去重 15. 三数之和 题目描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 …

全志H713红外IR遥控配置方法

篇头 全志H713 Soc是一颗 A53四核心&#xff0c;支持MAX 2GB DDR&#xff0c; 支持1920x1080P LVDS接口&#xff0c; 支持梯形校正功能的芯片&#xff0c;非常适合用于开发投影仪&#xff0c;尤其是低成本的LCD投影。本文详细介绍此平台&#xff0c;配置一个新的红外遥控器的方…

【无刷电机学习】电流采样电路硬件方案

【仅作自学记录&#xff0c;不出于任何商业目的】 目录 AD8210 INA282 INA240 INA199 AD8210 【AD8210数据手册】 在典型应用中&#xff0c;AD8210放大由负载电流通过分流电阻产生的小差分输入电压。AD8210抑制高共模电压(高达65V)&#xff0c;并提供接地参考缓冲输出&…

gtkmm xml ui 例子(from string)

文章目录 前言来看一个从字符串中生成UI的例子 前言 glade生成的xml格式不被gtkmm4支持, 需要作修改 来看一个从字符串中生成UI的例子 #include <gtkmm/application.h> #include <gtkmm.h> #include <iostream> using namespace std;class ExampleWindow :…

51单片机编程应用(C语言):独立按键

目录 1.独立按键介绍 2.独立按键控制LED亮灭 1.1按下时LED亮&#xff0c;松手LED灭&#xff08;按一次执行亮灭&#xff09; 1.2首先按下时无操作&#xff0c;松手时LED亮&#xff08;再按下无操作&#xff0c;所以LED亮&#xff09;&#xff0c;松手LED灭&#xff08;松手时…

音频几个相关概念及心理声学模型

系列文章目录 音频格式的介绍文章系列&#xff1a; 音频编解码格式介绍&#xff1a;音频几个相关概念及心理声学模型 https://blog.csdn.net/littlezls/article/details/135499627 音频编解码格式介绍&#xff1a;音频编码格式介绍 https://blog.csdn.net/littlezls/article/d…

RabbitMQ快速上手

首先他的需求实在什么地方。我美哟明显的感受到。 它给我的最大感受就是脱裤子放屁——多此一举&#xff0c;的感觉。 他将信息发送给服务端中间件。在由MQ服务器发送消息。 服务器会监听消息。 但是它不仅仅局限于削峰填谷和稳定发送信息的功能&#xff0c;它还有其他重要…

标准化编程系列(常用模式状态介绍)

任何事情任何编程都是有方法可循的,我们所要做的工作就是在看似没有规律的运行中,发现规律总结一般性的方法。这篇博客主要介绍标准化编程相关的基础知识,编程化编程离不开大家扎实的编程基本功,所以在学习标准化的同时,大家需要提升对于子程序,模块FB 、FC等的应用知识,…