Nacos配置中心客户端源码分析(一): 客户端如何初始化配置

本文收录于专栏 Nacos
推荐阅读:Nacos 架构 & 原理

文章目录

  • 前言
  • 一、NacosConfigBeanDefinitionRegistrar
  • 二、NacosPropertySourcePostProcessor
  • 三、AbstractNacosPropertySourceBuilder
  • 总结「AI生成」


前言

专栏前几篇文章主要讲了Nacos作为服务注册中心相关的代码,本章开始梳理Nacos作为配置中心来使用时相关部分的代码主要逻辑。

⚠️:使用的Nacos版本为2.3.X
⚠️:springboot集成Nacos

 <dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>0.2.12</version></dependency>

一、NacosConfigBeanDefinitionRegistrar

直接从spring.factories中找和心类:NacosConfigAutoConfiguration
在这里插入图片描述

@ConditionalOnProperty(name = NacosConfigConstants.ENABLED, matchIfMissing = true)
@ConditionalOnMissingBean(name = CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
@EnableConfigurationProperties(value = NacosConfigProperties.class)
@ConditionalOnClass(name = "org.springframework.boot.context.properties.bind.Binder")
@Import(value = { NacosConfigBootBeanDefinitionRegistrar.class })
@EnableNacosConfig
public class NacosConfigAutoConfiguration {
}

可以看到这个类里啥也没有,核心就是引入@EnableNacosConfig

@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(NacosConfigBeanDefinitionRegistrar.class)
public @interface EnableNacosConfig {//一些配置文件中nacos配置的占位符定义
}

我们来看关键类:NacosConfigBeanDefinitionRegistrar

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {AnnotationAttributes attributes = fromMap(metadata.getAnnotationAttributes(EnableNacosConfig.class.getName()));// Register Global Nacos Properties BeanregisterGlobalNacosProperties(attributes, registry, environment,CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);// Register Nacos Common BeansregisterNacosCommonBeans(registry);// Register Nacos Config BeansregisterNacosConfigBeans(registry, environment, beanFactory);// Invoke NacosPropertySourcePostProcessor immediately// in order to enhance the precedence of @NacosPropertySource processinvokeNacosPropertySourcePostProcessor(beanFactory);
}

invokeNacosPropertySourcePostProcessor上边的代码处理的都是和spring集成相关的逻辑,我们这里暂不去展开。invokeNacosPropertySourcePostProcessor通过这个名字我们可以简单看出来,这个方法处理的是post processor,一些后置逻辑。

二、NacosPropertySourcePostProcessor

public static void invokeNacosPropertySourcePostProcessor(BeanFactory beanFactory) {NacosPropertySourcePostProcessor postProcessor = beanFactory.getBean(//"nacosPropertySourcePostProcessor"NacosPropertySourcePostProcessor.BEAN_NAME,NacosPropertySourcePostProcessor.class);postProcessor.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

代码看到这里我们做个暂停,再次想一想我们到底要找什么,有了明确的方向才不至于在洋洋洒洒的源码里一头雾水。
那么,我们到底要找什么?

🏹对!我们想要知道的是Nacos是如何给@NacosValue标注的字段赋值的。🏹

然后再来看代码,是否就清晰了一点?

🏹对!代码中的关键词就是process🏹

那就继续看postProcessor.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory);

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException {String[] abstractNacosPropertySourceBuilderBeanNames = BeanUtils.getBeanNames(beanFactory, AbstractNacosPropertySourceBuilder.class);this.nacosPropertySourceBuilders = new ArrayList<AbstractNacosPropertySourceBuilder>(abstractNacosPropertySourceBuilderBeanNames.length);for (String beanName : abstractNacosPropertySourceBuilderBeanNames) {this.nacosPropertySourceBuilders.add(beanFactory.getBean(beanName,AbstractNacosPropertySourceBuilder.class));}NacosPropertySourcePostProcessor.beanFactory = beanFactory;this.configServiceBeanBuilder = getConfigServiceBeanBuilder(beanFactory);String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {processPropertySource(beanName, beanFactory);}
}

有了关键词,那我们就继续看processPropertySource(beanName, beanFactory);

private void processPropertySource(String beanName,ConfigurableListableBeanFactory beanFactory) {//processedBeanNames记录的是已经处理过的beanName, 看下这个方法的最后一行就知道了。if (processedBeanNames.contains(beanName)) {return;}//BeanDefinition:通过spring factory获取的bean定义类BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);// Build multiple instance if possibleList<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(beanName, beanDefinition);// Add Orderlyfor (NacosPropertySource nacosPropertySource : nacosPropertySources) {addNacosPropertySource(nacosPropertySource);Properties properties = configServiceBeanBuilder.resolveProperties(nacosPropertySource.getAttributesMetadata());addListenerIfAutoRefreshed(nacosPropertySource, properties, environment);}processedBeanNames.add(beanName);
}private List<NacosPropertySource> buildNacosPropertySources(String beanName,BeanDefinition beanDefinition) {for (AbstractNacosPropertySourceBuilder builder : nacosPropertySourceBuilders) {if (builder.supports(beanDefinition)) {return builder.build(beanName, beanDefinition);}}return Collections.emptyList();
}

builder.build(beanName, beanDefinition)
我们来着重看下这个方法

三、AbstractNacosPropertySourceBuilder

我们看下这个build方法的具体实现

public List<NacosPropertySource> build(String beanName, T beanDefinition) {Map<String, Object>[] attributesArray = resolveRuntimeAttributesArray(beanDefinition, globalNacosProperties);int size = attributesArray == null ? 0 : attributesArray.length;if (size == 0) {return Collections.emptyList();}List<NacosPropertySource> nacosPropertySources = new ArrayList<NacosPropertySource>(size);for (int i = 0; i < size; i++) {Map<String, Object> attributes = attributesArray[i];if (!CollectionUtils.isEmpty(attributes)) {NacosPropertySource nacosPropertySource = doBuild(beanName,beanDefinition, attributesArray[i]);NacosConfigMetadataEvent metadataEvent = createMetaEvent(nacosPropertySource, beanDefinition);initMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);publishMetadataEvent(metadataEvent);nacosPropertySources.add(nacosPropertySource);}}return nacosPropertySources;
}

这个方法返回的是List<NacosPropertySource>,而NacosPropertySource是在doBuild(beanName,beanDefinition, attributesArray[i]);这里给出的,那就着重看下这里的实现。

ps: 篇幅限制,只给出重要代码

protected NacosPropertySource doBuild(String beanName, T beanDefinition,Map<String, Object> runtimeAttributes) {//。。。String nacosConfig = nacosConfigLoader.load(dataId, groupId, nacosProperties);//。。。NacosPropertySource nacosPropertySource = new NacosPropertySource(dataId, groupId,name, nacosConfig, type);//。。。
}

NacosPropertySource中存放配置的位置:在这里插入图片描述

这个方法主要做了两件事:

  1. 获取 nacosConfig。我们知道,Nacos客户端在第一次获取数据的时候会去server端全量拉取一次,那所以这里肯定有和服务端交互的逻辑。
  2. 生成NacosPropertySource:这是doBuild要返回的数据。

总结「AI生成」

本文分析了Nacos客户端源码,重点探讨了Nacos作为配置中心的主要逻辑。以下是关键类的描述和功能总结:

  1. NacosConfigAutoConfiguration

    • 位于Spring的spring.factories中,负责自动配置Nacos。虽然类本身不包含逻辑,但通过@EnableNacosConfig注解引入了Nacos配置的核心类NacosConfigBeanDefinitionRegistrar
  2. NacosConfigBeanDefinitionRegistrar

    • 负责注册Nacos的相关Bean定义。主要方法registerBeanDefinitions包括注册全局Nacos属性、Nacos通用Bean和Nacos配置Bean,并调用NacosPropertySourcePostProcessor处理后置逻辑。
  3. NacosPropertySourcePostProcessor

    • 通过invokeNacosPropertySourcePostProcessor方法调用,负责后置处理逻辑,主要处理配置源的加载和Nacos属性的解析。其核心方法postProcessBeanFactory遍历所有Bean定义并处理Nacos配置源。
  4. AbstractNacosPropertySourceBuilder

    • 通过build方法构建NacosPropertySource。该方法首先解析运行时属性数组,然后根据属性构建Nacos配置源。核心方法doBuild实现了与Nacos服务端的交互,获取配置数据并生成NacosPropertySource
  5. NacosPropertySource

    • 存放从Nacos服务端获取的配置数据,是Nacos配置管理的核心数据结构。

本文通过深入分析这些关键类和方法,揭示了Nacos客户端在作为配置中心时的工作机制,特别是如何通过@NacosValue注解为字段赋值的流程。

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

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

相关文章

zram压缩机制看swapon系统调用

1.swapon开启zram交换分区 swapon /dev/block/zram0 mkswap /dev/block/zram0 上面命令调用了linux的swapon系统调用启动zram0交换分区;mkswap命令向块设备文件/dev/block/zram0写入了swap_header信息 问题:实际安卓平台是哪里触发swapon和mkswap调用的,我们已MTK8195平台…

平衡三进制类脑计算

PS:用来记录一些新奇又有趣的想法。。。 1、量子的世界 1.1薛定谔的猫 这感觉是个有趣的话题。 在宏观中可以观测到的&#xff0c;是稳定的两种状态&#xff0c;但随着尺寸不断缩小&#xff0c;直至达到微观尺度&#xff0c;这一切都变的有趣了起来&#xff0c;一只“既死又活…

zabbix server client 安装配置

Zabbix Server 采用源码包部署&#xff0c;数据库采用 MySQL8.0 版本&#xff0c;zabbix-web 使用 nginxphp 来实现。具体信息如下&#xff1a; 软件名 版本 安装方式 Zabbix Server 6.0.3 源码安装 Zabbix Agent 6.0.3 源码安装 MySQL 8.0.28 yum安装 Nginx 1.20…

Ubuntu20.04安装vimplus插件

参考文章&#xff1a; Ubuntu Linux下vimplus的安装及使用安装vimplus之后乱码问题解决 1、安装步骤&#xff1a; $ git clone https://github.com/chxuan/vimplus.git ~/.vimplus$ cd ~/.vimplus$ ./install.sh2、./install.sh 过程 出现选择是否备份 /home/yin-roc/.vim…

一个中文和越南语双语版本的助贷平台开源源码

一个中文和越南语双语版本的助贷平台开源源码。后台试nodejs。 后台 代理 前端均为vue源码&#xff0c;前端有中文和越南语。 前端ui黄色大气&#xff0c;逻辑操作简单&#xff0c;注册可对接国际短信&#xff0c;可不对接。 用户注册进去填写资料&#xff0c;后台审批&…

库存管理系统基于spingboot vue的前后端分离仓库库存管理系统java项目java课程设计java毕业设计

文章目录 库存管理系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 库存管理系统 一、项目演示 库存管理系统 二、项目介绍 基于spingboot和vue前后端分离的库存管理系统 功能模块&#xff…

热题系列章节7

剑指 Offer 04. 二维数组中的查找 题目描述&#xff1a; 在一个二维数组中&#xff08;每个一维数组的长度相同&#xff09;&#xff0c;每一行都按照从左到右递增的顺序排序&#xff0c;每一列都按照从上到下递增的顺序排序。请完成一个函数&#xff0c;输入这样的一个二维数…

Go 语言环境搭建

本篇文章为Go语言环境搭建及下载编译器后配置Git终端方法。 目录 安装GO语言SDK Window环境安装 下载 安装测试 安装编辑器 下载编译器 设置git终端方法 总结 安装GO语言SDK Window环境安装 网站 Go下载 - Go语言中文网 - Golang中文社区 还有 All releases - The…

策略模式在金融业务中的应用及其框架实现

引言 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为设计模式&#xff0c;它允许在不修改客户端代码的情况下&#xff0c;动态地改变一个类的行为。它通过定义一系列算法并将它们封装在独立的策略类中&#xff0c;使这些算法可以互相替换&#xff0c;而不会影响…

Spark Cache 的用武之地

在什么情况下适合使用 Cache 我建议你在做决策的时候遵循以下 2 条基本原则&#xff1a; 如果 RDD/DataFrame/Dataset 在应用中的引用次数为 1&#xff0c;就坚决不使用 Cache如果引用次数大于 1&#xff0c;且运行成本占比超过 30%&#xff0c;应当考虑启用 Cache第一条很好…

各维度卷积神经网络内容收录

各维度卷积神经网络内容收录 卷积神经网络&#xff08;CNN&#xff09;&#xff0c;通常是指用于图像分类的2D CNN。但是&#xff0c;现实世界中还使用了其他两种类型的卷积神经网络&#xff0c;即1D CNN和3D CNN。 在1D CNN中&#xff0c;内核沿1个方向移动。1D CNN的输入和…

高通Android 12 /13根据包名授权悬浮窗权限

代码路径frameworks/base/service/core/com/android/server/policy/PhoneWindowManager.java 1、 PhoneWindowManager.java中关于根据包名实现悬浮窗权限授权的功能实现 在实现根据包名授予悬浮窗权限的核心的功能开发中&#xff0c;在通过上述的功能原理实现的过程中分析得知…

EigenLayer 生态解析-再质押与 AVS 崛起

基于以太坊网络的再质押协议 EigenLayer 提出了利用为以太坊网络验证而质押的 ETH 来与其他协议共享安全性和资本效率,同时为协议参与者提供额外利息。在 AVS、再质押、积分系统等概念的推动下,逐渐形成一个庞大的生态系统,从 2024 年初到现在 EigenLayer 的 TVL 增加了 12 …

5.Spring IOC 循环依赖问题源码深度剖析

Spring IOC 容器解决循环依赖问题主要涉及到几个关键的缓存和对象创建过程中的处理逻辑。以下是对循环依赖问题进行深度剖析的概述&#xff1a; 循环依赖的背景 循环依赖发生在两个或多个Bean相互依赖对方&#xff0c;形成一个闭环。这可能是直接的&#xff0c;比如Bean A依赖B…

全球最大智能立体书库|北京:3万货位,715万册,自动出库、分拣、搬运

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 北京城市图书馆的立体书库采用了先进的WMS&#xff08;仓库管理系统&#xff09;和WCS&#xff08;仓库控制系统&#xff09;&#xff0c;与图书…

Linux磁盘监控思路分析

磁盘监控原理 设备又名I/O设备&#xff0c;泛指计算机系统中除主机以外的所有外部设备。 1.1 计算机分类 1.1.1 按照信息传输速度分&#xff1a; 1.低速设备&#xff1a;每秒传输信息仅几个字节或者百个字节&#xff0c;如&#xff1a;键盘、鼠标等 2.中速设备&#xff1a…

leetCode.98. 验证二叉搜索树

leetCode.98. 验证二叉搜索树 题目描述 代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(n…

100张linux C/C++工程师面试高质量图

文章目录 杂项BIOSlinux开机启动流程内核启动流程网络编程网络编程流程tcp状态机三次握手四次断开reactor模型proactor模型select原理poll原理epoll原理文件系统虚拟文件系统文件系统调用阻塞IO非阻塞IO异步IO同步阻塞同步非阻塞IO多路复用进程管理进程状态程序加载内存管理MMU…

力扣(2024.06.30)

1. 81——搜索旋转排序数组2 已知存在一个按非降序排列的整数数组 nums &#xff0c;数组中的值不必互不相同。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了旋转&#xff0c;使数组变为 [nums[k], n…

vue响应式原理细节分享

在讲解之前&#xff0c;我们先了解一下数据响应式是什么&#xff1f;所谓数据响应式就是建立响应式数据与依赖&#xff08;调用了响应式数据的操作&#xff09;之间的关系&#xff0c;当响应式数据发生变化时&#xff0c;可以通知那些使用了这些响应式数据的依赖操作进行相关更…