分布式之Nacos配置中心

Nacos作为配置中心源码分析

1、什么是Naocs配置中心

官方文档: https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config

Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。

2、Nacos的使用

2.1 给Nacos2.1.0配置数据库

倒入数据

image.png

修改内容

image.png

image.png

2.2 版本推荐

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

image.png

2.3 父工程指定版本

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version>
</parent>
<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><spring-cloud-alibaba.version>2.2.9.RELEASE</spring-cloud-alibaba.version>
</properties><dependencyManagement><dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

2.4 子工程引入依赖

 <dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--  单元测试类 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

2.5 利用接口对配置进行操作

public class ConfigListenerTest {private static String serverAddr = "localhost";private static String dataId = "nacos-demo.yaml";private static String group = "DEFAULT_GROUP";private static ConfigService configService;@Testpublic void testListener() throws NacosException, InterruptedException {Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);//获取配置服务configService = NacosFactory.createConfigService(properties);;//获取配置String content = configService.getConfig(dataId, group, 5000);System.out.println(content);//注册监听器CountDownLatch countDownLatch = new CountDownLatch(5);configService.addListener(dataId, group, new Listener() {@Overridepublic Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String configInfo) {System.out.println("配置发生变化:" + configInfo);countDownLatch.countDown();}});countDownLatch.await();}@Testpublic void publishConfig() throws NacosException {Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);//获取配置服务configService = NacosFactory.createConfigService(properties);configService.publishConfig(dataId,group,"age: 30", ConfigType.PROPERTIES.getType());}@Testpublic void removeConfig() throws NacosException, InterruptedException {Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);//获取配置服务configService = NacosFactory.createConfigService(properties);boolean isRemoveOk = configService.removeConfig(dataId, group);System.out.println(isRemoveOk);}}

2.6 和Springboot整合

@RefreshScope
@RestController
public class NacosConfigController {@Value("${name}")private String name;@RequestMapping("/getName")public String getName(HttpServletRequest httpRequest){return name;}
}

2.7 里面放置定时任务

启动

@EnableScheduling
@SpringBootApplication
public class NacosConfigApplication {public static void main(String[] args)  {SpringApplication.run(NacosConfigApplication.class);}
}

增加定时任务

@RestController
public class NacosConfigController {@Value("${name}")private String name;@RequestMapping("/getName")public String getName(HttpServletRequest httpRequest){return name;}// 定时任务每5秒执行一次@Scheduled(cron = "*/2 * * * * ?")public void execute(){System.out.println("获取姓名:" + name);}}

发现问题:如果我们更改配置,则对应的定时任务就失败

2.8 分析失败原因

2.8.1 Schedule执行原理

当我们更改配置的时候,我们看日志会进行容器的刷新

image.png

此时容器中并没有对应的NacosConfigController对应的实例对象。所以我们的定时任务不会执行,我们可以调用一下我们controller对应的方法,然后容器中就有了NacosConfigController对应的实例,有了这个实例,我们的定时任务就会执行,因为这个定时任务是基于后置处理器进行执行的。

image.png

2.8.2 @RefreshScope对象被清理的原因

那为什么刷新容器后NacosConfigController这Bean都没有了呢?

因为在我们更新配置后,我们的容器会将@RefreshScope标注的对象清掉,好我们来分析一下

image.png

image.png

Scope对应的有一个接口

image.png

image.png


image.png

image.png

真正实例创建 除了单例、多例、其他

image.png

我们分析这里从缓存中获取,

image.png

我们知道 单例获取是从单例对象池中,原型是重新构建Bean ,而我们Refresh是从BeanLifecycleWraperCache里面

image.png

image.png

image.png

image.png

也就是从缓存中获取对象,同时这里有个destroy

image.png

总结一下:

1、@RefreshScope中有个@Scope里面值是Refresh,他创建对象是放到对应的缓存中,我们通过GenericScope#get方法从缓存中获取对应Bean对象

2、我们更新数据的时候,会发送一个RefreshEvent事件,容器会监听这个事件,然后将缓存中数据进行删除

3、而我们定时任务是在创建bean的后置处理器中执行的,此时bean都被清理了,所以定时任务也没有了

4、我们再次访问对应的NacosConfigController的时候,我们就会创建对应的对象放到缓存,此时定时任务也就执行了

解决问题方案:

我们缓存删除是监听RefreshEvent事件而处理的,我们现在也可以监听事件进行处理,监听事件,如果事件发生,它回调用对应监听器,然后就会实例化,这样定时任务也可以执行

@Slf4j
@RefreshScope
@RestController
public class NacosConfigController implements ApplicationListener<RefreshScopeRefreshedEvent> {@Value("${name}")private String name;@RequestMapping("/getName")public String getName(HttpServletRequest httpRequest){return name;}// 定时任务每5秒执行一次@Scheduled(cron = "*/2 * * * * ?")public void execute(){System.out.println("获取姓名:" + name);}@Overridepublic void onApplicationEvent(RefreshScopeRefreshedEvent event) {log.info("监听刷新容器事件");}
}

3、源码分析

image.png

3.1 服务启动加载bootstrap.propertis

image.png

image.png

准备环境加载bootstrap.propertis,这里他会发送事件进行监听,我们可以直接进入 #load我们可以在load打上断点

image.png

总结:我们可以根据堆栈信息来发现,它是在准备环境的时候发送一个事件,ConfigFileApplicationListener监听事件,最后调用PropertiesPropertySourceLoader 对资源进行加载

3.2 客户端拉取远程配置进行合并

image.png

image.png

这里最终会调用用到NacosPropertySourceLocator# ,我们在locate上打上断点可以看一下堆栈信息

image.png

好,我们看一下locate方法

image.png

记载配置文件后最终会用composite进行合并,那他们无论加载共享配置、扩展配置和当前应用配置最终会调到NacosPropertySourceLocator#loadNacosDatalfPresent

image.png

image.png

image.pngimage.png

image.png

image.png

image.png

重点我们看一下他的配置加载

image.png

image.png

key1:从本地获取配置

image.png

key2:远程获取配置

image.png

image.png

image.png

总结:这里我们注意Spring的扩展点之一:在我们Bean构建之前加载一些数据,比如配置属性,我们就可以用这个扩展点,这里加载配置中心内容,这个内容用于后面bean对象创建。

例如:

image.png

进行配置

image.png

3.3 服务端处理配置拉取

image.png

客户端请求为ConfigQueryRequest,则从服务端进行搜索找到对应处理类

image.png

image.png

下面对应的方法比较长,我们可以看一下关键的点

image.png

image.png

总结:分析我们发送请求是从缓存文件中获取到的,这里带出两个问题,1、因为我们是从缓存中获取的,那我们直接修改数据库应该是不起作用的 2、缓存一定是从数据库中获取的,那什么时候设置进去的呢

3.4 服务启动进行数据库数据加载

image.png

image.png

服务端启动时就会依赖DumpService的init方法,从数据库中load 配置存储在本地磁盘上,并将一些重要的元信息例如MD5值缓存在内存中。服务端会根据心跳文件中保存的最后一次心跳时间,来判断到底是从数据库dump全量配置数据还是部分增量配置数据(如果机器上次心跳间隔是6h以内的话)。

全量dump当然先清空磁盘缓存,然后根据主键ID每次捞取一千条配置刷进磁盘和内存。增量dump就是捞取最近六小时的新增配置(包括更新的和删除的),先按照这批数据刷新一遍内存和文件,再根据内存里所有的数据全量去比对一遍数据库,如果有改变的再同步一次,相比于全量dump的话会减少一定的数据库IO和磁盘I0次数。

image.png

构建bean时候一定初始化@PostConstruct 对应的方法

image.png

判断全量和增量获取数据

image.png

image.png

全量拉取

image.png

image.png

image.png

image.png

总结:这里的md5值的我们学习,我们md5算法获取对应文件的值,如果这个值变化说明文件发生了变化,利用这中方式我们可以通过文件md5值来判断其他是否有变化

3.5 加载数据发生变更,发送事件

image.png

image.png

image.png

image.png

image.png

如果队列写满则如下操作:但是我们上面是服务启动暂时没有新的服务进来,所以这里subscriber是空的也就无法调用

image.png

如果正常情况下应该是放到队列里面,那就应该有取的地方,全文搜索对应的queue

image.png

哪里调用到这里呢?

image.png

image.png

从这里我们可以知道DefaultPublisher是一个线程,所有会调用run方法

总结:我们应该学会发布监听事件

3.6 监听配置变更

image.png

image.png

image.png

全文搜索ApplicationReadyEvent,查看NacosContextRefresher

image.png

image.png

image.png

发送RefreshEvent事件后,就是对@RefreshScope标志的实例进行删除,这里可以参考2.7分析失败原因

image.png

image.png

image.png

image.png

key1:销毁对应实例

image.png

key2:发送事件RefreshScopeRefreshedEvent 这也是我们通过监听这个事件,来实例化对应的实例的

3.7 服务端端更改配置

image.png

我们配置中心发布配置,一定是调用SpringMVC中的Controller方法 ,我们进行全文搜索,通过名称进行分析应该是ConfigController

image.png

image.png

image.png

key1: 更新数据库

image.png

image.png

image.png

key2:发布事件,进行客户端通知配置变更,以及集群同步

全文搜索ConfigDataChangeEvent

image.png

image.png

AsyncRpcTask是一个任务,并向里面传递了rpcQuene的一个任务队列,我看一下他是怎样处理的。

image.png

image.png

key1:我们看一下数据持久化, key2中集群数据同步就是发送一个rpc请求

我们重点key1:

image.png

image.png

image.png

image.png

上面我们解释过这里是异步处理一定有个地方处理他

image.png

image.png

image.png

image.png

image.png

image.png

发布LocalDataChangeEvent事件

全文搜索对应的事件

image.png

image.png

image.png

image.png

查看任务RpcPushTask对应的方法:

image.png

向客户端发送请求,进行配置变更的通知

image.png

3.8 客户端处理事件

image.png

我们知道发送请求的是ConfigChangeNotifyRequest,好,我们到客户端全文搜索一下,找对应的处理

image.png

image.png

我们全文搜索listenExecutebell找对应的处理位置

image.png

image.png

image.png

image.png

3.9 客户端定时拉取配置

image.png

image.png

image.png

image.png

image.png

3.10 于Nacos1.x长轮询做对比

image.png

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

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

相关文章

基于springboot+vue的乡政府管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Spring MVC文件上传配置

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 文件上传 Spring MVC文件上传基于Servlet 3.0实现&#xff1b;示例代码如下&#xff1a; Overrideprotected void customizeRegistration(ServletRegistration.Dynamic reg…

win10 配置 oh-my-posh

win10 配置 oh-my-posh 0. 前置1. 安装1.1. 软件1.2. 字体1.3. 激活1.3.1. Git Bash1.3.2. PowerShell 2. 配置2.1. 效果2.2. 说明2.3. 其他2.3.1. 新版PowerShell2.3.2 conda问题 0. 前置 这个东西毕竟是个&#xff0c;命令行美化工具&#xff0c;所以需要先有一个命令行&…

最后的挣扎 - Qt For Android on HuaWei Mate 60Pro (v4.0.0)

简介 为什么叫最后的挣扎, 其实都知道即将到来的 HarmonyOS NEXT 将抛弃Android支持&#xff0c;纯血HarmonyOS 将上线&#xff0c; 此时再说Qt for android支持Huawei HarmonyOS的设备其实并没有多少意思&#xff0c; 但恐怕在大多数基础软件完成兼容前&#xff0c; 很多人还是…

量子计算+HPC!ORNL与Riverlane、Rigetti合作研发

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 编辑丨慕一 编译/排版丨沛贤 1000字丨8分钟阅读 近日&#xff0c;英国量子计算初创公司Riverlane和美国量子计算公司Rigetti Computing宣布将参与由美国能源部橡树岭国家实验室&#xff08;OR…

【javaWeb】在webapp中手动发布一个应用

标题 &#x1f432;一、为什么要在webapp中手动发布一个应用&#x1f389;二、手动发布步骤1.下载Tomcat2.解压并安装3.在webapps中创建文档 ✨三、总结 &#x1f432;一、为什么要在webapp中手动发布一个应用 好处解释灵活性手动发布应用程序可以根据自己的需求进行自定义配置…

【C++】了解一下编码

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 前言2. ASCII编码3. unicode4. GBK5. 类型转换 1. 前言 看到string里面还有Template instantiations&#xff1a; string其实是basic_string<char>&#xff0c;它还是一个模板。 再看看wstring&#xff1…

195基于matlab的凸轮机构GUI界面

基于matlab的凸轮机构GUI界面 &#xff0c; 凸轮设计与仿真 绘制不同的凸轮轮廓曲线 &#xff0c;凸轮机构运动参数包括推程运动角&#xff0c;回程运动角&#xff0c;远休止角&#xff0c;近休止角。运动方式&#xff0c;运动规律。运动仿真过程可视化。内容齐全详尽。用GUI打…

el-select使用filterable下拉无法关闭得问题

这里推荐一个前端框架 sakuya / SCUI&#xff0c;他里面有个formTable&#xff0c;可以解决很多订单明细保存得问题。基本沿用element-plus的前端使用模式&#xff0c;让表单表格变的非常容易。 这个的供应商插件&#xff0c;当使用filterable后&#xff0c;点击表格重的选项&…

HarmonyOS NEXT应用开发—视频全屏切换案例

介绍 本示例介绍了Video组件和ohos.window接口实现媒体全屏的功能。 该场景多用于首页瀑布流媒体播放等。 效果图预览 使用说明&#xff1a; 点击全屏按钮&#xff0c;横屏媒体窗口。点击恢复窗口按钮&#xff0c;恢复媒体窗口。 实现步骤 在Video组件内调用 onFullscreen…

Gin 框架中前端向后端传值的几种方式介绍

我将为您详细讲解 Gin 框架中前端向后端传值的几种方式&#xff0c;并给出相应的简单例子。Gin 是一个高性能的 Web 框架&#xff0c;用于构建后端服务。在 Web 应用程序中&#xff0c;前端通常需要向后端发送数据&#xff0c;以便后端能够进行处理。以下是几种常见的前端向后端…

Vue2(六):生命周期、组件、组件的嵌套、VueComponent构造函数、单文件组件

一、生命周期 1.什么是生命周期&#xff1f; 生命周期 1.又名&#xff1a;生命周期回调函数、生命周期函数、生命周期钩子。 2.是什么&#xff1a;Vue在关键时刻帮我们调用的一些特殊名称的函数。 3.生命周期函数的名字不可更改&#xff0c;但函数的具体内容是程序员根据需求…

mybatis源码阅读系列(二)

前言 上一篇文章mybatis源码阅读系列&#xff08;一&#xff09;介绍了mybatis和原生jdbc的区别&#xff0c;并通过代码展示了两者的运行过程和结果&#xff0c;下面让我们继续详细了解下mybatis的执行过程&#xff1b; package com.wyl.mybatis.service;import com.wyl.mybat…

React三大属性---state,props,ref

react的三大属性 react的三大属性分别是state props 和ref 是传递数据的重要内容 State state是组件对象最重要的属性 包含多个key-value的组合呢 存在于组件实例对象中 基本使用 此时demo是通过onClick的回调 所以this是undefined 本来应该是window 但是局部开启了严格模…

【DL经典回顾】激活函数大汇总(十八)(ISRU附代码和详细公式)

激活函数大汇总&#xff08;十八&#xff09;&#xff08;ISRU附代码和详细公式&#xff09; 更多激活函数见激活函数大汇总列表 一、引言 欢迎来到我们深入探索神经网络核心组成部分——激活函数的系列博客。在人工智能的世界里&#xff0c;激活函数扮演着不可或缺的角色&a…

Android Studio 打包 Maker MV apk 详细步骤

一.使用RPG Make MV 部署项目&#xff0c;获取项目文件夹 这步基本都不会有问题&#xff1a; 二.安装Android Studio 安装过程参考教材就行了&#xff1a; https://blog.csdn.net/m0_62491877/article/details/126832118 但是有的版本面板没有Android的选项&#xff08;勾…

ES模块化

Node.js默认并不支持ES模块化&#xff0c;如果需要使用可以采用两种方式。方式一&#xff0c;直接将所有的js文件修改为mjs扩展名。方式二&#xff0c;修改package.json中type属性为module。 导出 默认导出 // 向外部导出内容 export let a 10 export const b "孙悟空…

Vue2 引入使用ElementUI详解

目录 1 安装2 引入2.1 全局引入2.1.1 引入2.1.2 使用 2.2 按需引入2.2.1 引入2.2.2 使用 3 总结 1 安装 推荐使用 npm 的方式安装&#xff0c;它能更好地和 webpack打包工具配合使用。&#xff08;本项目使用安装方式&#xff09; npm i element-ui -S也可以使用其他的包管理…

WebRTC:真正了解 RTP 和 RTCP

介绍 近年来&#xff0c;通过互联网进行实时通信变得越来越流行&#xff0c;而 WebRTC 已成为通过网络实现实时通信的领先技术之一。WebRTC 使用多种协议&#xff0c;包括实时传输协议 (RTP) 和实时控制协议 (RTCP)。 RTP负责通过网络传输音频和视频数据&#xff0c;而RTCP负责…

Java Swing游戏开发学习12

内容来自RyiSnow视频讲解 这一节讲的是实现游戏中的NPC(Non Player Character)非玩家角色。 添加了一个老人NPC&#xff0c;一个简单的AI&#xff08;人工智能&#xff09;拄着拐杖四处走。老人与树木、玩家的碰撞检测。 NPC四处走动 实现NPC四处走动 一开始&#xff0c;每一…