Spring Cloud Config配置信息自动更新原理解析

news2024/12/25 9:09:04

我们知道Spring Cloud Config是Spring Cloud提供的配置中心实现工具,我们可以通过它把配置信息存放在Git等第三方配置仓库中。每当Spring Cloud Config客户端启动时,就会发送HTTP请求到服务器端获取配置信息,这点比较好理解。但事实上,在Git中更改了配置信息之后,客户端并不会主动再次请求最新配置,而是使用缓存到本地的原有配置信息。


那么问题就来了,在这种情况下,Spring Cloud Config是如何能够实时获取更改后的配置呢?这就是今天我们要讨论的内容。通过理解Spring Cloud Config配置信息自动更新的执行过程,有助于我们深入把握框架的底层原理。

在对底层原理进行详细展开之前,我们先来给出Spring Cloud Config应对这一问题的具体做法。事实上,Spring Cloud Config能够做到配置信息的自动更新,是依赖于Spring Cloud中的另一个组件,即Spring Cloud Bus。

Spring Cloud Bus是Spring Cloud中用于实现消息总线的专用组件,集成了RabbitMQ、Kafka等主流消息中间件。当我们在Spring Cloud Config 服务器端代码工程的类路径中添加Spring Cloud Bus的引用并启动应用程序之后,Spring Boot Actuator就为我们提供了/actuator/bus-refresh端点,通过访问该端点就可以达到对客户端所有服务实例的配置信息进行自动更新的效果。在这种方案中,服务端会主动通知所有客户端进行配置信息的更新,这样我们就无需关注各个客户端,而只对服务端进行操作即可。

是不是听起来有点神奇?整个实现过程我们至少要搞清楚三大问题,如下图所示。


针对这三个问题,接下去我们将结合源码逐一展开讨论。

问题一:如何自动调用服务器端所暴露的/actuator/bus-refresh端点?

在现代软件开发过程中,开放式平台是一种常见的软件服务形态。我们可以把Spring Cloud Config Server所提供的HTTP端点视为一种开放式的接口,以供Git等第三方工具进行访问和集成。基于这种思想,我们可以把服务器端/actuator/bus-refresh端点对外进行暴露,然后第三方工具通过这个暴露的端点进行集成。例如,在Github中就设计了一种Webhook机制,并提供了用户界面供我们配置所需要集成的端点以及对应的操作,操作方法如下图所示。


我们可以在上图的Payload URL中设置/actuator/bus-refresh端点地址。所谓的Webhook,实际上就是一种回调。通过Webhook,当我们提交代码时,Github就会自动调用所配置的HTTP端点。也就是说,可以根据配置项信息的更新情况自动实现对/actuator/bus-refresh端点的访问。基于Github的配置仓库实现方案,我们可以得到如下图所示的系统结构图。


现在,配置信息一旦有更新,Spring Cloud Config Server就能从Github中获取最新的配置信息了。

问题二:客户端如何得知服务器端的配置信息已经更新?

接下来我们关注第二个问题,即客户端如何得知服务器端的配置信息已经更新?我们首先需要明确调用了/actuator/bus-refresh端点之后,系统内部会发生了么。这里我们快速浏览Spring Cloud Bus中的代码工程,发现存在一个RefreshBusEndpoint端点类,如下所示。

@Endpoint(id = "bus-refresh")

public class RefreshBusEndpoint extends AbstractBusEndpoint {

@WriteOperation

public void busRefreshWithDestination(@Selector String destination) {

//发布RefreshRemoteApplicationEvent事件

publish(new RefreshRemoteApplicationEvent(this, getInstanceId(), destination));

}

@WriteOperation

public void busRefresh() {

//发布RefreshRemoteApplicationEvent事件

publish(new RefreshRemoteApplicationEvent(this, getInstanceId(), null));

}

}

显然,RefreshBusEndpoint类对应于我们前面访问的/bus-refresh端点。可以看到,Spring Cloud Bus在这里做的事情仅仅只是发布了一个新的RefreshRemoteApplicationEvent事件。

既然发送了事件,我们就需要寻找该事件的监听者。我们在Spring Cloud Bus中找到了RefreshRemoteApplicationEvent事件的监听器RefreshListener,如下所示。

public class RefreshListener implements ApplicationListener<RefreshRemoteApplicationEvent> {

@Override

public void onApplicationEvent(RefreshRemoteApplicationEvent event) {

//执行配置属性的刷新操作

Set<String> keys = contextRefresher.refresh();

}

}

从类的定义中不难看出该监听器就是用来处理RefreshRemoteApplicationEvent事件。可以看到,在它的onApplicationEvent方法中同样也是调用了ContextRefresher中的refresh方法进行配置属性的刷新。

请注意,RefreshRemoteApplicationEvent是一个远程事件,将通过消息中间件进行发送,并被Spring Cloud Config客户端所监听,处理流程如下图所示。


问题三:客户端如何实时获取服务器端所更新的配置信息?

最后需要明确的第三个问题是,客户端如何获取服务器端所更新的配置信息,这就需要梳理Spring Cloud Config Server与注册中心之间的关系。

我们知道配置中心作为整个微服务架构运行所需的基础服务,需要确保其可用性。因为配置服务本身也是一个独立的微服务,所以Spring Cloud Config实现高可用的方式很简单。跟其他微服务一样,它把自己注册到注册中心上,让其他服务提供者或消费者通过注册中心进行服务发现和获取。


显然,在这种方式下,注册中心的服务治理机制同时提供了服务器端的负载均衡和客户端的配置功能,从而也就间接实现了高可用性。从另一个角度,我们也可以理解为可以通过注册中心获取所有Spring Cloud Config客户端服务的实例,从而在分布式环境下为获取配置信息提供了一种简便的手段。

Spring Cloud Config提供了一个工具类ConfigServerInstanceProvider来完成与注册中心之间的交互,如下所示。

public class ConfigServerInstanceProvider {

private final DiscoveryClient client;

  

@Retryable(interceptor = "configServerRetryInterceptor")

public List<ServiceInstance> getConfigServerInstances(String serviceId) {

List<ServiceInstance> instances = this.client.getInstances(serviceId);

if (instances.isEmpty()) {

//抛出异常

}

return instances;

}

}

在这里,我们看到了熟悉的DiscoveryClient,DiscoveryClient通过同样熟悉的getInstances方法从注册中心中获取Spring Cloud Config服务器实例,如下所示。

List<ServiceInstance> instances = this.client.getInstances(serviceId);

ConfigServerInstanceProvider的调用者是DiscoveryClientConfigServiceBootstrapConfiguration。我们来看这个Spring Boot自动配置类的定义,如下所示。

public class DiscoveryClientConfigServiceBootstrapConfiguration

implements SmartApplicationListener {

public void startup(ContextRefreshedEvent event) {

refresh();

}

}

可以看到,如果系统中生成了ContextRefreshedEvent事件就会触发如下所示的refresh方法。

private void refresh() {

try {

获取Spring Cloud Config客户端服务实例

String serviceId = this.config.getDiscovery().getServiceId();

List<String> listOfUrls = new ArrayList<>();

List<ServiceInstance> serviceInstances = this.instanceProvider.getConfigServerInstances(serviceId);

//遍历服务实例列表

for (int i = 0; i < serviceInstances.size(); i++) {

ServiceInstance server = serviceInstances.get(i);

String url = getHomePage(server);

  //获取配置路径

if (server.getMetadata().containsKey("configPath")) {

String path = server.getMetadata().get("configPath");

if (url.endsWith("/") && path.startsWith("/")) {

url = url.substring(0, url.length() - 1);

}

url = url + path;

}

  //填充配置路径

listOfUrls.add(url);

}

String[] uri = new String[listOfUrls.size()];

uri = listOfUrls.toArray(uri);

this.config.setUri(uri);

}

}

在上述refresh方法中,Spring Cloud Config首先会获取配置文件中配置项spring.cloud.config.discovery.serviceId所指定的服务实例id,然后根据serviceId从ConfigServerInstanceProvider中获取注册服务的实例对象集合serviceInstances,最后循环遍历serviceInstances来更新存储在内存中的配置属性值。

至此,我们通过解答三个问题,引出了Spring Cloud Config中实现配置信息自动更新的三个步骤,并基于框架内部一系列组件之间的交互过程剖析了底层实现原理。

总结

作为一个配置中心技术实现上的难点,今天的内容基于Spring Cloud Config框架剖析了实现配置信息自动更新的工作原理。我们抛出了三个与这个主题相关的核心问题,然后基于源码对这些问题都做了一一解答。

事实上,Spring Cloud Config作为Spring自研的配置中心框架,其内部大量使用了Spring现有的功能特性,比方说本讲中提到的Spring容器的事件发布和监听机制,又比方说Spring Boot Acuator中的端点机制以及Spring Cloud Bus所具备的消息通信总线机制。我们需要首先对Spring容器相关的知识体系有足够的了解,才能更好的理解Spring Cloud Config的设计和实现方式。

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

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

相关文章

一个示例学习C语言到汇编层面

给出以下代码 #include<stdio.h> int main() {int x 0, y 0, z 0;while (1) {x 0;y 1;do {printf("%d\n", x);z x y;x y;y z;} while (x < 255);}return 0; }我们把这个程序编写成32位程序&#xff0c;然后我们放入IDA中进行分析 .text:0080187…

矩阵乘法的直觉

矩阵乘法是什么意思&#xff1f; 一种常见的观点是矩阵乘法缩放/旋转/倾斜几何平面&#xff1a; NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜…

JavaScript妙笔生花:打造沉浸式中国象棋游戏体验

前言 随着信息技术的飞速发展&#xff0c;Web开发领域也出现了翻天覆地的变化。JavaScript作为前端开发中不可或缺的编程语言&#xff0c;其重要性不言而喻。而当我们谈论到利用JavaScript打造一款沉浸式的中国象棋游戏体验时&#xff0c;我们不仅仅是在开发一个游戏&#xff0…

Web应用安全测试-权限篡改

Web应用安全测试-权限篡改 任意用户密码修改/重置 漏洞描述&#xff1a; 可通过篡改用户名或ID、暴力破解验证码等方式修改/重置任意账户的密码。 测试方法&#xff1a; 密码修改的步骤一般是先校验用户原始密码是否正确&#xff0c;再让用户输入新密码。修改密码机制绕过方式…

【Ubuntu通用压力测试】Ubuntu16.04 CPU压力测试

​ 使用 stress 对CPU进行压力测试 我也是一个ubuntu初学者&#xff0c;分享是Linux的优良美德。写的不好请大佬不要喷&#xff0c;多谢支持。 sudo apt-get update 日常先更新再安装东西不容易出错 sudo apt-get upgrade -y 继续升级一波 sudo apt-get install -y linux-to…

微信分销商城小程序源码系统在线搭建 前后端分离 带完整的安装代码包以及搭建教程

系统概述 本微信分销商城小程序源码系统采用先进的前后端分离架构设计&#xff0c;前端使用Vue.js框架开发&#xff0c;后端则基于Spring Boot构建&#xff0c;确保了系统的高可维护性、扩展性和性能。系统集商品展示、在线交易、会员管理、分销推广、订单处理、数据统计等功能…

redis存储结构

概要 首先&#xff0c;redis是一种"键值对"&#xff08;key-value&#xff09;数据库&#xff0c;也就是说&#xff0c;redis中存储的用户数据都是以key-value的方式存在的&#xff0c;而这些键值对存储于哈希表&#xff0c;这也解释了为什么redis提供的set、lpush、…

vue标签组

先看样式 再看代码 <div v-else class"relative"><n-tabs ref"tabsInstRef" v-model:value"selectValue" class"min-w-3xl myTabs"><n-tab-panev-for"(tab) in songsTags" :key"tab.name" displ…

Java集合框架源码分析:ArrayList

文章目录 一、ArrayList特性二、ArrayList底层数据结构三、ArrayList继承关系1、Serializable标记性接口2、Cloneable标记性接口3、RandomAccess标记性接口4、AbstractList抽象接口 四、ArrayList源码分析1、构造方法2、添加方法3、删除方法4、修改方法5、获取方法6、转换方法7…

数据结构(DS)C语言版:学习笔记(4):线性表

参考教材&#xff1a;数据结构C语言版&#xff08;严蔚敏&#xff0c;吴伟民编著&#xff09; 工具&#xff1a;XMind、幕布、公式编译器 正在备考&#xff0c;结合自身空闲时间&#xff0c;不定时更新&#xff0c;会在里面加入一些真题帮助理解数据结构 目录 2.1线性…

青书学堂 看视频 耍课时

1. 获取课程节点id ( /nynzy/Student/Course/GetStudyRecordAndScore ) 接口地址 2. 把所有的nodeId 保存下来 保存到 old.txt 格式 课程id 与 nodeId 用 | 隔开 3. 然后创建 test.php 注意把 cookie 换成自己的 <?php$oldFilename ./old.txt; $newFilename ./new.…

idea插件开发之在项目右键添加菜单

写在前面 本文看下如何在右键列表中增加菜单。 正戏 首先创建一个Action&#xff0c;要显示的menu选择ProjectViewPopupMenu&#xff0c;如下&#xff1a; action public class CAction extends AnAction {Overridepublic void actionPerformed(AnActionEvent e) { // …

Excel 常用技巧(四)

Microsoft Excel 是微软为 Windows、macOS、Android 和 iOS 开发的电子表格软件&#xff0c;可以用来制作电子表格、完成许多复杂的数据运算&#xff0c;进行数据的分析和预测&#xff0c;并且具有强大的制作图表的功能。由于 Excel 具有十分友好的人机界面和强大的计算功能&am…

新项目Springboot报错: Whitelabel Error Page

问题&#xff1a; 新项目Springboot报错: Whitelabel Error Page 解析&#xff1a; 一般出现这个问题的原因就是目录结构不正确&#xff0c;导致主应用程序类&#xff08;Main application class&#xff09;扫描不到controller类。 默认情况下主应用程序类&#xff08;Main …

【Git】win本地 git bash:Connect reset by 20.205.243.166 port22报错问题解决

win10 git bash 控制台 reset 22端口拒绝连接问题&#xff1a; Connection reset by 20.205.243.166 port 221、22端口 无法连接 ssh -T gitgithub.com2、尝试用443端口 仍然无法连接 ssh -T -P 443 gitgithub.com3、重写 git clone 地址 url&#xff0c;全局添加 https 前缀…

从零到一,深入浅出大语言模型的奇妙世界

2022 年底&#xff0c;OpenAI 发布的 ChatGPT 模型在全球范围内引起了巨大轰动。本文详细的介绍了大语言模型的发展历程、构建过程和大语言模型如何使用等知识&#xff0c;帮助大家搞懂大语言模型。 一、大语言模型发展历程 大模型技术并不是一蹴而就的&#xff0c;大语言模型…

Neo4j Desktop界面认识以及数据库备份与还原

Neo4j Desktop界面认识以及数据库备份与还原 neo4j 版本信息&#xff1a;Neo4j Desktop Version 1.5.9&#xff1b;neo4j 5.12.0 系统信息&#xff1a;windows 11 Neo4j Desktop 界面 每个 Project 下可以有多个 DBMS&#xff0c;而每个 DBMS 中默认有 system 和 neo4j (def…

揭秘全自动高速开箱机:智能与精细化,打造高效生产

在现代化生产的浪潮中&#xff0c;全自动高速开箱机以其高效、智能的特点&#xff0c;成为众多行业提升生产效率的得力助手。与星派一起走进全自动高速开箱机的世界&#xff0c;探寻其高效背后的智能与精细。 全自动高速开箱机&#xff0c;是一种能够自动完成开箱操作的机械设备…

微信答题扫码答题自己能做吗?微信扫二维码答题快速制作的方法介绍!

在数字化时代&#xff0c;微信扫码答题已经成为一种流行的互动方式&#xff0c;它不仅便捷高效&#xff0c;而且能够极大地提升参与者的体验感。这种新型的答题方式&#xff0c;通过微信平台的广泛覆盖和用户友好的操作界面&#xff0c;为企业和组织提供了一个创新的知识传播和…

25. 一个双高斯照相物镜的设计

导论&#xff1a; 双高斯照相物镜的设计思想&#xff0c;当β-1时&#xff0c;由于其对称&#xff0c;彗差、畸变和倍率色差自动校正为0&#xff0c;利用中间两块厚透镜可以校正场曲&#xff0c;选取合适的光阑位置可以校正像散&#xff0c;在厚透镜中加胶合面使每个半部校正位…