【Spring Boot 源码学习】BootstrapContext的实际使用场景

《Spring Boot 源码学习系列》

在这里插入图片描述

BootstrapContext的实际使用场景

  • 一、引言
  • 二、往期内容
  • 三、主要内容
    • 3.1 BootstrapContext
    • 3.2 BootstrapRegistry 初始化器实现
    • 3.3 BootstrapContext 的实际使用场景
      • 3.3.1 早期启动时
      • 3.3.2 环境配置准备完成时
      • 3.3.3 应用上下文准备完成后关闭 `BootstrapContext`
    • 3.4 实际使用演示
  • 四、总结

一、引言

上一篇博文《BootstrapRegistry 初始化器实现》,Huazie 向大家介绍了如何自定义 BootstrapRegistryInitializer 接口实现,并以此来执行自定义的初始化操作【如注册自定义的 Bean、添加 BootstrapContext 关闭监听器】。其中涉及到了 BootstrapContext 的部分使用场景,那本篇就向大家演示下 Spring Boot 启动过程中如何使用引用上下文 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 源码学习】BootstrapRegistry 初始化器实现

三、主要内容

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

3.1 BootstrapContext

在 《深入 BootstrapContext 及其默认实现》 中,Huazie 详细介绍了引导上下文 BootstrapContext 及其默认实现 DefaultBootstrapContext,在继续下面的内容之前,有不知道的朋友们可以去回顾一下,这里不再赘述。

3.2 BootstrapRegistry 初始化器实现

在开始讲解 BootstrapContext 的实际使用场景之前,我们需要首先通过 BootstrapRegistry 初始化器实现类 注册自定义的对象,以便后续在实际的场景中通过 BootstrapContext 来获取。

这块内容,有需要了解的朋友,请翻看 Huazie 的上一篇博文《BootstrapRegistry 初始化器实现》,这里不再赘述。

3.3 BootstrapContext 的实际使用场景

首先我们需要通过源码来明确下需要 添加哪些内容,哪些场景和引导上下文有关?

先来看如下的截图【SpringApplication##run】:

在这里插入图片描述

从上面可以看到 BootstrapContext 实际上有 3 处使用场景,分别是:

  • 早期启动时
  • 环境配置准备完成时
  • 应用上下文准备完成后关闭 BootstrapContext

3.3.1 早期启动时

首先我们来看看 早期启动时 的源码截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从上述截图可知,这里多播了 ApplicationStartingEvent 事件,我们如果想要监听这个事件,只需要实现对应的事件监听器,并添加到监听器列表 listeners 中即可。

下面我们来自定义有关 ApplicationStartingEvent 事件的监听器类:

public class DemoStartingListener implements ApplicationListener<ApplicationStartingEvent>, Ordered {@Overridepublic void onApplicationEvent(ApplicationStartingEvent event) {ConfigurableBootstrapContext bootstrapContext = event.getBootstrapContext();User user = bootstrapContext.get(User.class);System.out.println("启动时获取User:" + user);user.setName("Huazie_1");user.setAge(19);}@Overridepublic int getOrder() {return 1;}
}

上述代码中的 User 类只是一个简单的 POJO 对象,这里源码就不列出来了,可以自行定义即可。

那么上述自定义的监听器该如何添加到监听器列表 listeners 中呢?

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

  • META-INF/spring.factories 中添加 org.springframework.context.ApplicationListener 的配置。这种方式,我们从 《ApplicationListener 详解》 的 3.2 小节可见一斑。
  • 通过 SpringApplication 中的 addListeners 方法添加。这里其实在笔者的《SpringApplication 的定制化介绍》中的 1.7 小节也提及过。

有关监听器实现 Ordered 接口,这里再次提及下:它可以用来确保多个监听同一事件的监听器可以按照我们预定的顺序执行。

3.3.2 环境配置准备完成时

接着,我们来看看 准备环境配置 的源码截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从上述截图可知,这里显然在环境配置准备完成之后,多播了 ApplicationEnvironmentPreparedEvent 事件,我们如果想要监听这个事件,只需要实现对应的事件监听器,并添加到监听器列表 listeners 中即可。

下面我们来自定义有关 ApplicationEnvironmentPreparedEvent 事件的监听器类:

public class DemoEnvironmentPreparedListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {@Overridepublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {ConfigurableBootstrapContext bootstrapContext = event.getBootstrapContext();if (bootstrapContext.isRegistered(User.class)) {User user = bootstrapContext.get(User.class);System.out.println("环境准备时获取User:" + user);user.setName("Huazie_2");user.setAge(20);}}@Overridepublic int getOrder() {return 1;}
}

至于该监听器如何添加到监听器列表 listeners 中,显然跟 3.4.1 中的 DemoStartingListener 一样,等下会通过 SpringApplication 进行添加演示。

3.3.3 应用上下文准备完成后关闭 BootstrapContext

最后,我们看看准备应用上下文的源码截图:

在这里插入图片描述
在这里插入图片描述

从上述截图中,我们可以看出的确是在应用上下文准备完成后,调用了 DefaultBootstrapContextclose 方法,多播了 BootstrapContextClosedEvent 事件。我们如果想要监听这个事件,只需要实现对应的事件监听器,不过添加该监听器就不像 3.4.13.4.2 那样了。其实在 3.2 小节介绍的《BootstrapRegistry 初始化器实现》中,我们已经介绍了如何添加 BootstrapContext 关闭事件 监听器,这里就不再赘述。

3.4 实际使用演示

BootstrapContext 的实际使用场景已经在 3.3 中介绍,下面 Huazie 就带大家实操下。

首先,Spring Boot 启动类中需要修改如下:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(DemoApplication.class);// 关闭 Banner打印springApplication.setBannerMode(Banner.Mode.OFF);// 添加 BootstrapRegistry初始化器实现springApplication.addBootstrapRegistryInitializer(new DemoBootstrapper());// 添加 监听器实现springApplication.addListeners(new DemoStartingListener(), new DemoEnvironmentPreparedListener());springApplication.run(args);}
}

修改好启动类的代码,我们就可以来运行了,如下截图:

在这里插入图片描述
从上述截图中,我们可以看到 3.3 中介绍的 3 个实际使用场景,已经全部打印日志信息了,说明定义的监听器已经执行了。

四、总结

本篇 Huazie 通过介绍 BootstrapContext 的实际使用场景,并演示了引导上下文在这些场景的实际使用,加深了大家对于 Spring Boot 的启动引导过程的了解,为后续的源码分析打下基础。

后续的博文,Huazie 就将从 SpringApplicationrun 方法入手,开始介绍 Spring Boot 的运行流程,敬请期待!

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

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

相关文章

Android增量报告生成新方案

在开发精准测试覆盖率相关的功能时候&#xff0c;对于Android的增量报告&#xff0c;由于担心修改jacoco插件会影响App的打包&#xff0c;所以一直没有修改。在网上查了一下&#xff0c;没有找到合适的方案。只有一个diff-cover开源项目&#xff1a;https://github.com/abmaonl…

Yolov8-pose关键点检测:SPPF创新涨点篇 | SPPELAN:SPP创新结合ELAN ,效果优于SPP、SPPF| YOLOv9

💡💡💡本文独家改进:新颖SPPF创新涨点改进,SPP创新结合ELAN,来自于YOLOv9,助力YOLOv8-pose,将SPPELAN代替原始的SPPF SPPELAN结构图如下: Yolov8-Pose关键点检测专栏介绍:https://blog.csdn.net/m0_63774211/category_12398833.html ✨✨✨手把手教你从数据标…

计算机网络——23网络层导论

网络层导论 网络层服务 在发送主机和接收主机对之间传送段&#xff08;segment&#xff09;在发送端将段封装到数据报中在接收端&#xff0c;将段上交给传输层实体网络层协议存在于每一个主机和路由器路由器检查每一个经过它的IP数据报的头部 网络层的关键功能 网络层功能 …

C#,老鼠迷宫问题的回溯法求解(Rat in a Maze)算法与源代码

1 老鼠迷宫问题 迷宫中的老鼠&#xff0c;作为另一个可以使用回溯解决的示例问题。 迷宫以块的NN二进制矩阵给出&#xff0c;其中源块是最左上方的块&#xff0c;即迷宫[0][0]&#xff0c;目标块是最右下方的块&#xff0c;即迷宫[N-1][N-1]。老鼠从源头开始&#xff0c;必须…

MySQL 篇-快速了解事务、索引

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 事务概述 1.1 事务四大特性(ACID) 2.0 索引概述 2.1 关于 “索引一定要创建在主键上&#xff1f;” 的问题 2.2 索引操作语法 2.3 索引结构 1.0 事务概述 事务是…

JavaWeb实验 JSP内置对象

实验目的 掌握JSP内置对象的使用&#xff1b;内置对象包括out\request\response\cookie等。 实验内容 【1】创建一个JSP网页&#xff0c;文件名为index.jsp&#xff0c;利用request内置对象获取客户端访问ip的功能&#xff0c;屏蔽用户利用局域网实际ip访问Web&#xff0c;但…

技术选型思考:分库分表和分布式DB(TiDB/OceanBase) 的权衡与抉择

在当今数据爆炸的时代&#xff0c;数据库作为存储和管理数据的核心组件&#xff0c;其性能和扩展性成为了企业关注的重点。随着业务的发展和数据量的不断增长&#xff0c;传统的单库单表架构逐渐暴露出性能瓶颈和扩展性限制。为了应对这些挑战&#xff0c;企业常常需要在分库分…

15. C++泛型与符号重载

【泛型编程】 若多组类型不同的数据需要使用相同的代码处理&#xff0c;在C语言中需要编写多组代码分别处理&#xff0c;这样做显然太过繁琐&#xff0c;C增加了虚拟类型&#xff0c;使用虚拟类型可以实现一组代码处理多种类型的数据。 虚拟类型是暂时不确定的数据类型&#…

数据中台:数字中国战略关键技术设施

文章目录 每日一句正能量前言为何要建设数据中台数据中台建设痛点数据中台学习资料聚焦前沿&#xff0c;方法论体系更新与时俱进&#xff0c;紧跟时代热点深入6大行业&#xff0c;提炼实践精华大咖推荐&#xff0c;数字化转型必备案头书购买链接赠书活动 每日一句正能量 人生之…

找不到本地组策略编辑器解决办法

创建记事本写入以下命令 echo offpushd "%~dp0"dir /b %systemroot%\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >gp.txtdir /b %systemroot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-…

Django会话

一、Cookie介绍 1.1、背景介绍 HTTP协议有一个特性就是无状态的,是指协议对于交互性场景没有记忆能力 随着动态交互的web应用的出现,HTTP的无状态特性严重阻碍了动态交互应用程序的发展,例如一些购物网站在进行购物时候都会进行了页面跳转/刷新,按照HTTP的无状态协议岂不…

Compose UI 之 MediumLarge TopAppBar

Medium&Large TopAppBar 前面文章介绍了 Small 类型的 TopAppBar&#xff1a;TopAppBar CenterAlignedTopAppBar 。下来介绍 Medium 和 Large 类型的 TopAppBar&#xff1a;MediumTopAppBar LargeTopAppBar 。 MediumTopAppBar 上面介绍了Small 类型的 TopAppBar (TopAp…

实战|环信 Vue2 uniapp Demo重构焕新!经典再升级!

项目背景 当前环信 uni-app vue2 Demo 地址升级版本 Github 地址&#xff08;临时&#xff09; 原版本功能实现方式较混乱&#xff0c;代码逻辑晦涩难懂&#xff0c;不利于开发者参考或复用。此实战项目在确保原项目功能保留的情况下进行完全重写并新增大量功能&#xff0c;以…

【C语言】指针相关知识点

什么是指针&#xff1f; 指针&#xff08;Pointer&#xff09;是编程语言中的一个对象&#xff0c;利用地址&#xff0c;它的值直接指向&#xff08;points to&#xff09;存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元&#xff0c;可以说&#xff0c;地…

Golang搭建grpc环境

简介 OS : Windows 11 Golang 版本: go1.22.0 grpc : 1.2 protobuffer: 1.28代理 没有代理国内环境下载不了库七牛CDN &#xff08;试过可用&#xff09; go env -w GOPROXYhttps://goproxy.cn,direct阿里云代理(运行grpc时下载包出现报错 ): go env -w GOPROXYhttps://mirr…

黑马点评-异步秒杀实现

异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是…

Axure Cloud如何给每个原型配置私有域名

需求 在原型发布之后&#xff0c;自动给原型生成一个独立访问的域名&#xff0c;类似http://u591bi.axshare.bushrose.cn&#xff0c;应该如何配置呢&#xff1f; 准备事项 已备案域名 如何备案&#xff1f;阿里云备案流程 已安装部署Axure Cloud 如何安装部署&#xff0c;请…

WordPress建站入门教程:如何创建菜单和设置前端导航菜单?

前面我们跟大家分享了WordPress如何上传安装WordPress主题&#xff0c;但是启用主题后前端没有看到有导航菜单&#xff0c;这是因为我们还没有创建菜单和设置导航菜单。 JianYue主题导航菜单和右上角菜单 今天boke112百科就继续跟大家分享WordPress站点如何创建菜单和设置前端…

Kafka入门及生产者详解

1. Kafka定义 传统定义&#xff1a;分布式的、基于发布/订阅模式的消息队列&#xff0c;主要用于大数据实时处理领域。发布/订阅模式中&#xff0c;发布者不会直接将消息发送给特定的订阅者&#xff0c;而是将发布的消息分为不同的类别&#xff0c;订阅者只接受感兴趣的消息。…

Linux系统Docker部署DbGate并结合内网穿透实现公网管理本地数据库

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-66GkyG9g7oNq7tl8 {font-family:"trebuchet ms",verdana,arial,sans-serif;f…