【BlossomConfig】SpringCloud项目是如何对bootstrap配置文件进行加载的?

文章目录

  • bootstrap配置文件的读取
  • 什么是配置中心?以及如何实现一个配置中心?
  • SpringBoot如何实现配置的管控?
  • SpringCloud项目是如何对bootstrap配置文件进行加载的?
  • Nacos是如何实现配置文件的读取加载的?
  • 开发配置中心前必须了解的前置知识
  • 配置中心Server和Client端代码的编写
  • 配置中心Core核心功能代码的编写
  • 配置中心源码优化---本地缓存与读写锁

网关项目源码
RPC项目源码
配置中心项目源码

bootstrap配置文件的读取

我们首先来了解一下springboot是如何做配置管理的。
了解了springboot对配置文件的管理,我们就能知道为什么springcloud类型的项目要使用bootstrap配置文件了。
关于SpringBoot是如何加载application和bootstrap配置文件的底层原理这里就不再次赘述了,大家可以移步到知识星球内部的如下位置进行学习。
在这里插入图片描述

简单回忆一下,既然和配置文件相关,那么我们找到spring的run方法中的如下这行代码然后往下分析即可。

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);

因为通过上面的学习我们知道Environment中存储了我们项目的所有配置信息。
这里我们着重分析一下这一行代码中都做了多少事情。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {ConfigurableEnvironment environment = this.getOrCreateEnvironment();this.configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(bootstrapContext, environment);DefaultPropertiesPropertySource.moveToEnd(environment);Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");this.bindToSpringApplication(environment);if (!this.isCustomEnvironment) {EnvironmentConverter environmentConverter = new EnvironmentConverter(this.getClassLoader());environment = environmentConverter.convertEnvironmentIfNecessary(environment, this.deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;
}

首先是基于当前环境,创建一个环境对象。
在这里插入图片描述
这里由于我们的项目是Web项目,所以创建的是:StandardServletEnvironment
并且这里会层层的通过extends的继承关系,不断的初始化父类。
最终,又会回到子类的实现。
在这里插入图片描述
在这里插入图片描述
通过我们前面的了解,我们知道,其实这些代码的作用就是往容器末尾不断的添加配置文件的信息。
不过上面的创建的是系统的环境,而我们自己编写的配置文件的信息的加载,并不是在这里完成的。
我们最终读取配置文件的代码,是通过监听器的方式来完成的。

listeners.environmentPrepared(bootstrapContext, environment);

而事件监听是spring提供的一个非常重要的扩展机制,很多功能我们都可以基于监听器这种方式来实现。
我们只需要负责发布事件,对应的事件监听器就执行相应的代码来处理这个事件。
可以发现,在我们的环境创建好之后,然后就会发布一个环境预备的事件。那么此时就等待对应的监听器进行处理即可。

public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}

事件发布之后,通过层层的下叠,最终,spring通过拿到所有注册的监听器的方式,让这些监听器判断当前事件是否是由自己处理的,如果是,就处理当前事件即可。
在这里插入图片描述
在这里插入图片描述
这里我们可以知道,其实我们发布的就是一个环境预备完成的事件。
按图索骥即可。
在这里插入图片描述
继续往下找,就会发现,通过迭代器的方式,会通过这些后置处理器对我们的配置文件信息进行处理。
在这里插入图片描述
再早期的版本中,用的是ConfigFile进行配置文件处理。
在这里插入图片描述
只不过版本高了就废弃了,而是用其他几个。
不过大致的意思也差不多。
因此,到此为止,其实我们大概就知道了,当项目流程到达这一步的时候,其实Spring做的事情就是通过IO流的方式去读取所有的配置文件信息,并且对他们进行解析。
在这里插入图片描述
这里我们跳到看ConfigDataEnvironment即可
在这里插入图片描述
因此,通过上面我们可以看到,只要我们再规定的位置编写配置文件,spring就可以帮助我们去加载这些配置文件。
并且,我们也可以通过实现自己的监听器的方式,再触发对应的环境准备完毕事件之后,使用我们的监听器去处理我们的配置文件。
这里,我通过实现一下按照上面的方法,实现监听器的方式,来加载配置文件信息。
特别注意, 在 Spring Boot 中,ApplicationEnvironmentPreparedEvent事件发生在 ApplicationContext 创建之前,这意味着使用 @Component 或 @Configuration 注解的方式无法确保监听器被及时注册。
相反,我需要在应用启动时手动注册该监听器。或者使用spring.factories的方式来完成自动装配。

# Application Listeners
org.springframework.context.ApplicationListener=\
blossom.project.config.core.listener.BootstrapApplicationListener
package blossom.project.config.core.listener;import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.stereotype.Component;import java.io.InputStream;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;/*** @author: ZhangBlossom* @date: 2023/12/26 22:33* @contact: QQ:4602197553* @contact: WX:qczjhczs0114* @blog: https://blog.csdn.net/Zhangsama1* @github: https://github.com/ZhangBlossom* BootstrapListener类* 用于在项目启动的时候通过环境准备事件完成对bootstrap配置文件的读取加载* 特别注意* 在 Spring Boot 中,ApplicationEnvironmentPreparedEvent* 事件发生在 ApplicationContext 创建之前,* 这意味着使用 @Component 或 @Configuration 注解的方式无法确保监听器被及时注册。* 相反,我需要在应用启动时手动注册该监听器。*/
//@Component
//@Configuration
//@AutoConfiguration
public class BootstrapListenerimplements ApplicationListener<ApplicationEnvironmentPreparedEvent> {static {System.out.println("成功被加载...");}@Overridepublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {MutablePropertySources propertySources = event.getEnvironment().getPropertySources();Properties properties = new Properties();try {InputStream inputStream = BootstrapListener.class.getClassLoader().getResourceAsStream("bootstrap" +".properties");properties.load(inputStream);ConcurrentHashMap<Object,Object> cache = new ConcurrentHashMap<>();for (Map.Entry<Object, Object> entry : properties.entrySet()) {cache.put(entry.getKey(),entry.getValue());}propertySources.addLast(new OriginTrackedMapPropertySource("bootstrap.properties",properties));}catch (Exception e){e.printStackTrace();}}
}
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class ConfigApplication {public static void main(String[] args) {SpringApplication app = new SpringApplication(ConfigApplication.class);app.addListeners(new BootstrapListener());ConfigurableApplicationContext context = app.run(args);BootstrapListener bean = context.getBean(BootstrapListener.class);System.out.println(bean);ConfigurableEnvironment environment = context.getEnvironment();System.out.println(environment);}
}

运行代码之后发现,成功了。
在这里插入图片描述
当然,我还发现了另一种解决方法,就是使用@PropertySource注解。
但是使用这个注解的一个问题在于他只能解析比较常规的配置文件。对于txt这种应该是解析不了。
而且很明显,我们不应该再代码中硬编码。所以我个人比较倾向于使用监听器的方式去解析配置文件。

@Configuration
@PropertySource("classpath:bootstrap.yml")
public class PropertySourceConfig {
}

因此,我们的第一个问题,如何处理bootstrap类型的文件的问题,就已经解决了。

接下来我们可以研究一下,Nacos是如何实现配置文件的加载的,这也对我们上面分析的逻辑有确定作用。

什么是配置中心?以及如何实现一个配置中心?

SpringBoot如何实现配置的管控?

SpringCloud项目是如何对bootstrap配置文件进行加载的?

Nacos是如何实现配置文件的读取加载的?

开发配置中心前必须了解的前置知识

配置中心Server和Client端代码的编写

配置中心Core核心功能代码的编写

配置中心源码优化—本地缓存与读写锁

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

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

相关文章

一次普通的漏洞挖掘思路分享

No.0 前言 一名web安全小白&#xff0c;自己仅学了一点思路&#xff0c;直接实战&#xff0c;运气不错&#xff0c;碰到了管理员弱口令&#xff0c;进入后台后&#xff0c;继续测试自己学会的思路挖掘深一点的漏洞&#xff0c;这里与各位分享一下&#xff0c;如果有更多的思路…

MMU关闭时Cache的缓存策略是怎样的

快速链接: 【精选】ARMv8/ARMv9架构入门到精通-[目录] &#x1f448;&#x1f448;&#x1f448; 在学习MMU章节时&#xff0c;我们发现在页表的entry中&#xff0c;BIT[4:2]指向了MAIR寄存器&#xff0c;该寄存器描述了内存属性&#xff0c;其实就是cache的缓存策略属性&#…

洛谷-P1706 全排列问题(DFS)

目录 题目链接&#xff1a; 思路&#xff1a; 代码&#xff1a; 题目链接&#xff1a; P1706 全排列问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路&#xff1a; 如果n比较小&#xff0c;可以写n个for循环输出全排列。但是这种简单方法只能用于较小的n&#xff0…

Vue依赖注入,详细解析

Prop 逐级透传问题​ 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。想象一下这样的结构&#xff1a;有一些多层级嵌套的组件&#xff0c;形成了一颗巨大的组件树&#xff0c;而某个深层的子组件需要一个较远的祖先组件中的部分数据。…

C++心决之内联函数+auto关键字+指针空值

目录 7.内联函数 7.1 概念 7.2 特性 8. auto关键字(C11) 8.1 类型别名思考 8.2 auto简介 8.3 auto的使用细则 8.4 auto不能推导的场景 9. 基于范围的for循环(C11) 9.1 范围for的语法 9.2 范围for的使用条件 10. 指针空值nullptr(C11) 10.1 C98中的指针空值 7.内联…

水质监测站:守护水源,筑牢水质安全屏障

TH-LSZ06水质监测站&#xff0c;作为现代水质监测技术的创新成果&#xff0c;以其高效、便捷的特点&#xff0c;在水源保护、环境监测等领域发挥着越来越重要的作用。它不仅能够实时监测水质变化&#xff0c;提供准确的数据支持&#xff0c;还能为水质安全管理提供科学依据&…

深入理解Java内存模型及其作用

目录 1.前言 2.为什么要有 Java 内存模型&#xff1f; 2.1 一致性问题 2.2 重排序问题 3.Java 内存模型的定义 4.规范内容 4.1 主内存和工作内存交互规范 4.2 什么是 happens-before 原则&#xff1f; 1.前言 当问到 Java 内存模型的时候&#xff0c;一定要注意&#…

idea编译一直失败处理

切换分支的时候&#xff0c;明明代码正常&#xff0c;但是编译的时候一直失败。。。。特别是多个项目的时候&#xff0c;经常失败。 配置 -Djps.track.ap.dependenciesfalse idea默认是增量编译&#xff0c;设置这个false之后就从头开始编译了。 设置之后&#xff0c;点击编译&…

基于springboot的实习生管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

蓝桥杯每日不知道多少题之昂贵的聘礼

制作不易望点赞收藏加关注~~~&#xff0c;以便不时之需 题目连接&#xff1a;903. 昂贵的聘礼 - AcWing题库 解题思路&#xff1a;虚拟一个物品0&#xff0c;然后反向建边&#xff0c;边权为物品0到物品i所花费的价格&#xff0c;以及物品i换物品j所省下的钱&#xff0c;然后…

超机购ERP管理系统都有哪些功能模块?

在经济下行周期&#xff0c;众多手机店家正逐步向高效化和智能化迈进&#xff0c;手机行业作为数码产品的重要分支&#xff0c;正迎来前所未有的变革机遇。咱们超机购ERP系统&#xff0c;凭借对市场的敏锐洞察与技术创新&#xff0c;推出了超机系列工具&#xff0c;旨在引领手机…

docker容器技术篇:Docker API配置与常用操作

docker容器技术篇&#xff1a;Docker API配置与使用 一、API具体是什么&#xff1f; 百科解释应用程序接口&#xff08;API&#xff09;&#xff0c;又称为应用编程接口&#xff0c;就是软件系统不同组成部分衔接的约定&#xff0c;蒙了吧&#xff01;&#xff01;&#xff0…