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

news2024/11/24 20:36:19

文章目录

  • 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 BootstrapListener
        implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    static {
        System.out.println("成功被加载...");
    }

    @Override
    public 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.coloradmin.cn/o/1563871.html

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

相关文章

2024年4月腾讯云最新活动:领3150元代金券礼包,新购、续费、升级可用!

腾讯云推出大促优惠活动&#xff1a;免费领取3150元代金券礼包&#xff1b;云服务器、云数据库、COS等上云必备产品&#xff0c;低至1.8折起&#xff1b;云产品助力企业和开发者轻松上云&#xff01; 活动入口&#xff1a;https://txy.ink/act/ 活动详情&#xff1a; 1、新人…

顺序表的创建

本期我们主要讨论动态顺序表 这个内容可以分为三个部分 1.创建头文件进行函数声明 2.创建源文件进行函数定义 3.创建主文件进行测试 我们先来看看头文件里的函数声明&#xff1a; 函数声明&#xff1a; 头文件中包括<stdlib.h>库函数用于进行动态内存管理&#xff0…

【攻防世界】warmup (代码审计)

进入题目环境&#xff0c;只有一个表情&#xff1a; ctrl u 查看源代码&#xff1a; 源代码提示我们访问 /source.php。访问结果如下&#xff1a; 我们进行代码审计&#xff0c;发现解题的关键点 include &_REQUEST[file]。但是题目使用了白名单进行了过滤。我们发现白名单…

C++bitset类型

bitset类型 我们介绍了将整型运算对象当作二进制位集合处理的一些内置运算符。 标准库还定义了bitset类&#xff0c;使得位运算的使用更为容易&#xff0c;并且能够处理超过最长整型类型大小的位集合。bitset类定义在头文件bitset中。 定义和初始化bitset bitset类是一个类模…

近屿智能独家发布行业领先的AIGC学习路径图

近日来“人工智能即将取代大量人类工作”的话题愈演愈烈&#xff0c;在CCTV-13的《两会你我他》访谈节目中&#xff0c;众多专家也围绕这一议题展开了深入的讨论&#xff0c;AI不会取代你的工作&#xff0c;会取代你的是懂AI技术的人。李强总理在访谈中也强调了推动"人工智…

【NTN 卫星通信】卫星辅助补充下行数据应用场景

1 卫星辅助下行数据场景概述 在乡村地区向地面接入网覆盖欠佳或无线电条件(例如山谷地区)的用户提供无线接入网可能无法提供所需的服务性能。   增加补充下行数据容量(例如由NTN提供)将有助改善服务性能和QoE&#xff0c;例如支援与视讯消费有关的流量不对称。因此&#xff0…

SpringBoot:自定义线程池配置类

文章目录 一、前言二、案例展示1、初始版本2、代码审核意见和优化建议3、潜在问题和风险4、优化建议5、优化后的代码 三、具体使用 一、前言 有时候我们在项目中做一些长链路的跑批任务时&#xff0c;基于Springboot项目的定时任务&#xff0c;我们可以指定一个自定义的线程配…

C-偶遇行军蚁(遇到过的题,做个笔记)

我的代码: 思路就是把每一行看成一个字符串&#xff0c;然后逐渐增加字符就行 #include <iostream> #include <vector> using namespace std; int main() {string s;int n;cin >> n; //读入行数cin >> s; //读入字符串vector<string>arr(n…

一起来从Solidworks中导出URDF模型

这个博客是用来记录关于【从Solidworks中导出URDF模型】的学习历程&#xff1a; 相关课程链接见&#xff1a;如何从Solidworks导出URDF模型 • 古月 (guyuehome.com) 下面让我们一起开始吧&#xff01;&#xff01;&#xff01; 1. sw_urdf_exporter插件介绍 插件下载链接&…

共享社会经济路径(SSP1-5)中国及分省人口预估数据库_v2

v1数据集&#xff1a; 在共享社会经济路径&#xff08;SSPs&#xff09;全球框架下&#xff0c;根据本地化人口和经济参数&#xff0c;采用人口-发展-环境&#xff08;PDE&#xff09;模型&#xff0c;构建2020-2100年SSPs人口格点数据&#xff1b;采用柯布-道格拉斯&#xff…

基于STM32的汽车防窒息系统

文章目录 基于STM32的汽车防窒息系统系统简介材料展示视频制作硬件连接原理图PCB实物图GSM模块使用GSM模块代码 SGP30模块SGP30模块代码 步进电机驱动步进电机代码 其他模块主逻辑代码 总结 基于STM32的汽车防窒息系统 系统简介 随着社会的发展目前汽车的流行&#xff0c;汽车大…

vSAN vs SmartX 超融合:BI 数仓跑批效率对比测试

在《VMware 与 SmartX 分布式存储缓存机制浅析与性能对比》中&#xff0c;我们分析了 vSAN 7 缓存击穿的问题及其原因。近期&#xff0c;某金融用户在进行数据仓库分布式存储选型时&#xff0c;同样遭遇了测试过程中 vSAN 出现缓存击穿而难以完成全量跑批任务的问题。随后&…

安卓Android 架构模式及UI布局设计

文章目录 一、Android UI 简介1.1 在手机UI设计中&#xff0c;坚持的原则是什么1.2 安卓中的架构模式1.2.1 MVC (Model-View-Controller)设计模式优缺点 1.2.2 MVP(Model-View-Presenter)设计模式MVP与MVC关系&#xff1a; 1.2.3 MVVM(Model—View—ViewModel ) 设计模式1.2.4 …

ssm018简易版营业厅宽带系统+jsp

营业厅宽带系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本营业厅宽带系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间…

群晖NAS使用Docker部署大语言模型Llama 2结合内网穿透实现公网访问本地GPT聊天服务

文章目录 1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 随着ChatGPT 和open Sora 的热度剧增,大语言模型时代,开启了AI新篇章,大语言模型的应用非常广泛&#xff0c;包括聊天机…

新发现!科学家最新成果:补充类“原知因起源金”物质可延长寿命23%

近日&#xff0c;美哥伦比亚大学Vijay Yadav团队在《Science》发布了一项重磅级成果&#xff1a;通过补充一种特殊氨基酸&#xff08;带有磺酸基团的全能抗衰物质&#xff09;&#xff0c;竟然惊人地将实验动物的寿命延长了23%。 而其背后的机制&#xff0c;与早已火爆电商圈的…

Git命令(1)[删除,恢复与移动]

文章目录 1.删除文件1.1命令----rm <filename>1.2命令----git rm <filename>1.1命令----git rm <filename> -f 2.恢复文件2.1命令----git restore <filename>2.1命令----git restore --staged <filename> 3.重命名文件3.1命令----mv <oldFile…

javaweb学习(day10-服务器渲染技术)

一、基本介绍 1.前言 目前主流的技术是 前后端分离 (比如: Spring Boot Vue/React)JSP 技术使用在逐渐减少&#xff0c;但使用少和没有使用是两个意思&#xff0c;一些老项目和中小公司还在使用 JSP&#xff0c;工作期间&#xff0c;你很有可能遇到 JSPJSP 使用在减少(但是现…

分布式唯一ID 雪花算法

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 算法具体介绍 雪花算法是 64 位 的二进制&#xff0c;一共包含了四部分&#xff1a; 1位是符号位&#xff0c;也就是最高位&#xff0c;…

基于Weibull、Beta、Normal分布的风、光、负荷场景生成及K-means场景削减方法

目录 一、主要内容&#xff1a; 二、代码运行效果&#xff1a; 三、Weibull分布与风机风速&#xff1a; 四、Beta分布与光伏辐照度&#xff1a; 五、Normal分布与电负荷&#xff1a; 六、K-means聚类算法&#xff1a; 七、完整代码数据下载&#xff1a; 一、主要内容&am…