【Spring Boot 源码学习】BootstrapRegistry 初始化器实现

《Spring Boot 源码学习系列》

在这里插入图片描述

BootstrapRegistry 初始化器实现

  • 一、引言
  • 二、往期内容
  • 三、主要内容
    • 3.1 BootstrapRegistry
    • 3.2 BootstrapRegistryInitializer
    • 3.3 BootstrapRegistry 初始化器实现
      • 3.3.1 定义 DemoBootstrapper
      • 3.3.2 添加 DemoBootstrapper
  • 四、总结

一、引言

前面的博文《BootstrapRegistryInitializer 详解》,Huazie 带大家一起详细分析了 Spring Boot 启动时加载并初始化 BootstrapRegistryInitializer 及其相关的类的逻辑。本篇就让我们自定义 BootstrapRegistryInitializer 接口实现,以此来执行自定义的初始化操作【如注册自定义的 Bean、添加 BootstrapContext 关闭监听器】。

在这里插入图片描述

二、往期内容

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

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 源码学习】BootstrapRegistry 详解
【Spring Boot 源码学习】深入 BootstrapContext 及其默认实现

三、主要内容

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

3.1 BootstrapRegistry

在《BootstrapRegistry 详解》 中,Huazie 详细介绍了 BootstrapRegistry 的源码,这有助于下面介绍的 BootstrapRegistry 初始化器的实现逻辑,有不知道的朋友们直接查看即可,这里不再赘述。

3.2 BootstrapRegistryInitializer

在《BootstrapRegistryInitializer 详解》 中,Huazie 详解分析了加载并初始化 BootstrapRegistryInitializer 的逻辑,这同样有助于
理解下面将要讲解的内容,还不熟悉的朋友们赶紧花点时间了解下,这里不再赘述。

3.3 BootstrapRegistry 初始化器实现

3.3.1 定义 DemoBootstrapper

下面我们来定义一个类 DemoBootstrapper,该类实现 BootstrapRegistryInitializer 接口,如下:

public class DemoBootstrapper implements BootstrapRegistryInitializer {@Overridepublic void initialize(BootstrapRegistry registry) {// 注册一些自定义的对象 或者 加载自定义的一些配置}
}

在《BootstrapRegistryInitializer 详解》 的 3.2 小节,Huazie 介绍了 BootstrapRegistryInitializer 的加载过程,上述我们自定义的 DemoBootstrapper 也会在 Spring Boot 启动引导阶段进行加载并初始化。

上述定义中,我们只是展示了一个空实现的类,其中的 initialize 方法还未做处理。

至于 initialize 方法中该添加哪些逻辑,这就要看它的参数 BootstrapRegistry 接口了。

下面代码,Huazie 演示了如何 注册自定义的对象,以及添加 引导上下文关闭事件监听器

// 注册 User对象,它就是一个简单的 POJO 类,含两个成员变量:名称 name 和年龄 age
registry.register(User.class, context -> new User("Huazie", 18));
// 添加 BootstrapContext关闭 监听器
registry.addCloseListener(new DemoBootstrapContextClosedListener());

DemoBootstrapContextClosedListener ,即引导上下文关闭事件监听器,相关演示代码如下:

public class DemoBootstrapContextClosedListener implements ApplicationListener<BootstrapContextClosedEvent>, Ordered {@Overridepublic void onApplicationEvent(BootstrapContextClosedEvent event) {BootstrapContext bootstrapContext = event.getBootstrapContext();if (bootstrapContext.isRegistered(User.class)) {System.out.println("BootstrapContext关闭时获取User:" + bootstrapContext.get(User.class));}}@Overridepublic int getOrder() {return 1;}
}

虽然上面添加了引导上下文关闭事件监听器,但是我们还不知道什么时候它会被执行。

DemoBootstrapContextClosedListener 中,我们看到了 BootstrapContext 的使用,显然这里涉及到了引导上下文的实际使用场景,由于篇幅受限,将在下篇介绍,大家不妨期待一下。

另外,在 DemoBootstrapContextClosedListener 中,还看到它实现了 Ordered 接口【spring-core 包中的接口】。

那么在事件监听器中,这个 Ordered 接口是用来做什么的呢?

在回答这个问题之前,我们先来看看 Ordered 接口的源码:

public interface Ordered {int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;int LOWEST_PRECEDENCE = Integer.MAX_VALUE;int getOrder();
}

Ordered 接口定义了两个常量和一个方法:

  • HIGHEST_PRECEDENCE:最高优先级值的有用常数【最小的 Integer 值】
  • LOWEST_PRECEDENCE :最低优先级值的有用常数【最大的 Integer 值】
  • int getOrder() :获取当前对象的优先级值【值越小,优先级越高】

源码中对于 Ordered 接口是这样说的:

它可以被需要排序的对象实现,例如在集合中。实际的排序可以被解读为优先级排序,其中第一个对象(即有着最低的排序值)具有最高的优先级。

当然,Ordered 接口还有一个扩展接口,即优先级标记接口 PriorityOrderedPriorityOrdered 对象总是优先于普通 Ordered 对象,无论它们的排序值如何。当对一组 Ordered 对象进行排序时,PriorityOrdered 对象和普通 Ordered 对象实际上被视为两个独立的子集,PriorityOrdered 对象子集先于普通 Ordered 对象子集,并在这些子集内部应用相对排序。

上述排序逻辑请查看 spring-core 包中的 AnnotationAwareOrderComparator 类 和 OrderComparator 类,这里不再赘述了。

现在可以回答上面的问题了:在事件监听器中实现 Ordered 接口,可以用来确保 多个监听同一事件的监听器 可以按照我们 预定的顺序执行

3.3.2 添加 DemoBootstrapper

不过,要想能够加载到自定义的 DemoBootstrapper ,我们还需要将它添加到 bootstrapRegistryInitializers 中才可以。

// SpringApplication的私有变量
private List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;

那么,我们该如何添加呢?

通过阅读 SpringApplication 的源码,可以总结如下的两种方式:

  • META-INF/spring.factories 中添加 org.springframework.boot.BootstrapRegistryInitializer 的配置。这种方式,我们从 《BootstrapRegistryInitializer 详解》 的 3.2 小节可见一斑。

    org.springframework.boot.BootstrapRegistryInitializer=com.example.demo.DemoBootstrapper
    
  • 通过 SpringApplication 中的 addBootstrapRegistryInitializer 方法添加。其实这里在笔者的《SpringApplication 的定制化介绍》中的 1.5 小节也提及过。

    SpringApplication springApplication = new SpringApplication(DemoApplication.class);
    springApplication.addBootstrapRegistryInitializer(new DemoBootstrapper());
    // 其他省略。。。
    

四、总结

本篇 Huazie 介绍了如何自定义 BootstrapRegistry 初始化器实现,其中演示如何在引导上下文中注册了自定义的对象以及如何在引导上下文中添加引导上下文关闭事件监听器

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

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

相关文章

代码随想录算法训练营第46天| 139.单词拆分、背包问题总结

139.单词拆分 完成 思路&#xff1a; 本题可以用背包问题的思路解决&#xff0c;单词是物品&#xff0c;字符串是背包&#xff0c;要求物品能否把背包装满。 dp[j] 字符串长度为j时&#xff0c;能否拆分为一个或多个在字典中出现的单词。 递推公式为&#xff1a;if([i, j] 这个…

【Java文件报错】Cannot resolve symbol ‘println‘ 【及解决】

一、问题描述 在Java源代码文件中&#xff0c;使用 System.out.println() 语句进行输出&#xff0c;编译器提示“Cannot resolve symbol ‘println’&#xff08;无法解释关键字&#xff09;”, println飘红。报错代码及报错截图如下所示。 import java.io.*;public class St…

Leetcode560. 和为 K 的子数组 -hot100

题目&#xff1a; 代码(首刷看解析 2024年3月2日&#xff09;&#xff1a; class Solution { public:int subarraySum(vector<int>& nums, int k) {// 前缀和 遍历int res 0;unordered_map<int, int> sumPre;int sum 0;// 关键&#xff1a;初始化sumPre[0]…

特征融合篇 | YOLOv8 引入通用高效层聚合网络 GELAN | YOLOv9 新模块

今天的深度学习方法专注于如何设计最合适的目标函数,以使模型的预测结果最接近真实情况。同时,必须设计一个合适的架构,以便为预测提供足够的信息。现有方法忽视了一个事实,即当输入数据经过逐层特征提取和空间转换时,会丢失大量信息。本文将深入探讨数据通过深度网络传输…

nn.Linear() 使用提醒

原本以为它是和nn.Conv2d()一样&#xff0c;就看第二个维度的数值&#xff0c;今天才知道&#xff0c;它是只看最后一个维度的数值&#xff01;&#xff01;&#xff01; 例子1 Descripttion: Result: Author: Philo Date: 2024-02-27 14:33:50 LastEditors: Philo LastEditT…

Windows命令行工具和PowerShell介绍

Windows命令行工具和PowerShell是两种不同的文本界面命令解释器&#xff0c;它们在Windows操作系统中用于执行各种操作和管理任务。虽然它们都可以用于执行命令和脚本&#xff0c;但它们之间存在着一些区别和特点。 1. Windows命令行工具&#xff08;Cmd.exe&#xff09; …

xxl-job--01--简介

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.xxl-job1. 1 发展历史1.2 XXL-JOB的系统架构1.3 xxl-job与其他框架对比 2. XXL-JOB的使用2.1 准备工作- 配置调度中心XXL-JOB的数据表 2.2 配置执行器1 引入依赖包…

2023,九章云极DataCanvas的澎湃时刻

大模型和AIGC成就了2023。九章云极DataCanvas公司的2023充满生命力&#xff0c;是人工智能基础软件创新浓度最高的一年&#xff0c;也是价值释放最具想象力的一年。 人工智能新时代的热潮席卷而来&#xff0c;九章云极DataCanvas公司以过硬的AI技术响应时代&#xff0c;冲锋智…

Datawhale【Sora原理与技术实战】| 学习笔记

目录 一. Sora能力二. Sora训练流程1. Visusal encoder2. Diffusion Transformer3. Transformer Decoder 一. Sora能力 长视频&#xff1a;最大可支持60s高清视频生成保持人物与场景高度统一视频融合能力强同一场景多角度/多镜头涌现&#xff1a;随着运动镜头的变化&#xff0…

中央处理器CPU中的技术

一、 知识加油站 1. cpu 指令的执行过程 取指&#xff1a;cpu 获取 程序计数器 中存放的指令地址。读取内存中此地址对应指令并存入指令寄存器译码&#xff1a;指令译码器&#xff0c;解析指令运行&#xff1a;算数逻辑单元计算回写&#xff1a;将执行结果写入对应位置 二. …

Julia语言中的位运算符、赋值运算符、算术运算符

算术运算符 # 使用基本的赋值运算符 a 10 println("a 的初始值是: $a") # 使用加法赋值运算符 a 5 println("a 加上 5 后的值是: $a") # 使用减法赋值运算符 - a - 3 println("a 减去 3 后的值是: $a") # 使用乘法赋值运算符…

spring框架Bean的作用域?对需要保持会话状态的bean应使用prototype作用域?为啥?

当一个bean被定义为"prototype"作用域时&#xff0c;每次请求该bean时都会创建一个新的实例&#xff0c;而不是像"singleton"作用域那样共享同一个实例。 对于需要保持会话状态的bean&#xff0c;如果使用"singleton"作用域&#xff0c;会导致所…