Nacos 配置共享
Nacos 配置共享
功能简介
Nacos 以命名空间实现多租户强隔离,默认各命名空间间配置互不可见。为满足多集群、跨命名空间的配置共享需求,Nacos 配置共享功能嵌入 Spring Cloud 生命周期,兼容 Nacos 配置监听与动态刷新。
更新记录
- v3.1.2 初次实现
GAV 坐标
implementation(commonLibs.blade.nacos.share.spring.boot.starter)<dependency>
<groupId>team.aikero.blade</groupId>
<artifactId>blade-nacos-share-spring-boot-starter</artifactId>
</dependency>快速集成
- 选择合适的 GAV,在项目中添加依赖。
implementation(commonLibs.blade.nacos.share.spring.boot.starter)- 在项目的
application.yaml中添加下方代码。
blade:
nacos:
share:
# 共享配置所在的命名空间
namespaces:
- public
# 是否覆盖组别,默认为 false 时,取路径参数 或 `spring.cloud.nacos.config.group` 配置
override-group: false
# 指定共享配置所在的组,`override-group: true` 时生效
group: DEFAULT_GROUP提示
Nacos 配置共享的配置信息必须在 Nacos 远程配置之前提供,否则功能无法生效。
Spring 配置文件加载顺序如下:spring.config.location(如application.yml)spring.config.additional-locationspring.config.import
因此,建议在application.yml或spring.config.additional-location中直接配置。
blade.web.cloud.spring.boot.starter已引入,若使用 web-cloud 组件无需单独引入此依赖。
详细说明
配置示例
默认情况下,yunwei-config 提供 Nacos 配置共享功能
若有特殊定制需求可以在application.yml文件中,可以进行以下配置:
blade:
nacos:
share:
# 共享配置所在的命名空间
namespaces:
- public
# 是否覆盖组别,默认为 false 时,取路径参数 或 `spring.cloud.nacos.config.group` 配置
override-group: false
# 指定共享配置所在的组,`override-group: true` 时生效
group: DEFAULT_GROUP代码示例
引入包即可
配置文件优先级
- 优先使用当前命名空间下的配置。
- 若当前命名空间无配置,则按
blade.nacos.share.namespaces顺序查找并加载第一个存在的配置。
提示
此处仅为共享配置文件的优先级,是单个配置文件的查找及加载顺序。配置属性优先级依旧遵循 Spring Boot 优先级。
优先级示例
相关信息
先说结论:
在不覆盖组别时,配置文件的灵活性更高,需要维护的配置文件数量更多,需要使用方明确指定分组。
在覆盖分组时,配置文件的灵活性更低,需要维护的配置文件数量更少,不需要使用方明确指定分组。
环境配置
现有服务 example-service 配置如下:
spring:
application:
name: example-service
cloud:
nacos:
config:
namespace: dev-ola
server-addr: http://localhost:8848
group: test
config:
import:
# 跨命名空间,同组
- optional:nacos:share-config-test-group.yml
# 跨命名空间,自定义组
- optional:nacos:share-config-share-group.yml?group=share
# 跨命名空间,自定义组
- optional:nacos:external-config-share-group.yml
# 同命名空间,自定义组
- optional:nacos:nonshared-config-share-group.yml?group=share
- optional:nacos:${spring.application.name}
blade:
nacos:
share:
namespaces:
- dev-nest
- publicNacos 中有配置如下:namespace=dev-ola
| namespace | group | Data Id |
|---|---|---|
| dev-ola | test | example-service |
| dev-ola | share | nonshared-config-share-group.yml |
namespace=dev-nest
| namespace | group | Data Id |
|---|---|---|
| dev-nest | test | share-config-test-group.yml |
| dev-nest | share | share-config-share-group.yml |
| dev-nest | share | external-config-share-group.yml |
namespace=public
| namespace | group | Data Id |
|---|---|---|
| public | share | external-config-share-group.yml |
配置情景-覆盖组别
blade:
nacos:
share:
override-group: true
group: share此时覆盖组别信息,example-service实际能够加载以下配置:namespace=dev-ola; group=test; 和 namespace=dev-nest,public; group=share;
配置详见下表:
| namespace | group | Data Id | 说明 |
|---|---|---|---|
| dev-ola | test | example-service | 同命名空间,同组 |
| dev-ola | share | nonshared-config-custom-group.yml | 同命名空间,不同组,由路径参数(group=share)指定分组 |
| dev-nest | share | external-config-share-group.yml | 不同命名空间,不同组,由配置分组(blade.nacos.share.group=share)参数加载 |
| dev-nest | share | share-config-share-group.yml | 不同命名空间,不同组,由配置分组(blade.nacos.share.group=share)覆盖路径参数加载 |
| dev-nest/public | test | share-config-test-group.yml | 共享分组不匹配,未加载 |
Nacos 日志如下:
[Nacos Config] Load config[dataId=example-service, group=test] success
[Nacos Config] Load config[dataId=nonshared-config-share-group.yml, group=share] success
[Nacos Config] Load config[dataId=external-config-share-group.yml, group=test] success <-- 此处 Nacos 日志分组信息输出错误,但不影响实际配置加载,因 Nacos 的编码方式无法扩展,无法覆盖此日志输出
[Nacos Config] Load config[dataId=share-config-share-group.yml, group=share] success
[Nacos Config] config[dataId=share-config-test-group.yml, group=test] is empty配置情景-不覆盖组别
blade:
nacos:
share:
override-group: false此时未覆盖组别信息,example-service 实际能够加载以下配置:namespace=dev-ola,dev-nest,public; group=test;
配置详见下表:
| namespace | group | Data Id | 说明 |
|---|---|---|---|
| dev-ola | test | example-service | 同命名空间,同组 |
| dev-ola | share | nonshared-config-custom-group.yml | 同命名空间,不同组,由路径参数指定分组 |
| dev-nest/public | share | external-config-share-group.yml | 分组不匹配,未加载 |
| dev-nest | share | share-config-share-group.yml | 不同命名空间,不同组,由路径参数指定分组 |
| dev-nest | test | share-config-test-group.yml | 不同命名空间,同组 |
Nacos 日志如下:
[Nacos Config] Load config[dataId=example-service, group=test] success
[Nacos Config] Load config[dataId=nonshared-config-share-group.yml, group=share] success
[Nacos Config] config[dataId=external-config-share-group.yml, group=test] is empty
[Nacos Config] Load config[dataId=share-config-share-group.yml, group=share] success
[Nacos Config] Load config[dataId=share-config-test-group.yml, group=test] success在以上两个情景中,始终不会加载 namespace=public 下的配置,按blade.nacos.share.namespaces中命名空间的定义顺序,始终会先从 namespace=dev-nest 中加载到配置external-config-share-group.yml。
实现方案
Nacos Config 实现简介
ConfigData 机制的核心设计
Spring Boot 2.4+ 引入的 ConfigData 机制是配置加载的核心重构,其目标是通过标准化接口实现多源配置的统一加载,并支持动态刷新能力。该机制包含以下核心组件:
ConfigDataResource
定义配置资源的抽象表示(如本地文件路径、远程配置中心地址、数据库连接等),
例如:
•ClasspathResource:类路径下的配置文件
•NacosConfigResource:Nacos 配置中心的 Data ID 和 GroupConfigDataLocationResolver
负责将用户配置的spring.config.import参数解析为具体的ConfigDataResource集合。
例如:
• 解析nacos:example-config.yaml为 Nacos 远程配置资源NacosConfigResourceConfigDataLoader
根据ConfigDataResource资源信息加载配置内容,并转换为PropertySource对象注入Environment。
例如:
• 从 Nacos 拉取配置并解析为键值对
• 处理配置加密、Profile 激活等扩展逻辑
ConfigData 加载时机与流程
ConfigData 的加载发生在 Spring Boot 启动的引导阶段(BootstrapContext),早于大部分 Bean 初始化,具体流程如下:
环境准备阶段(prepareEnvironment)
• 解析spring.config.import参数,调用ConfigDataLocationResolver生成资源列表资源加载阶段
• 通过ConfigDataLoader加载所有资源,合并到Environment中
Spring Cloud Nacos Config 的实现方式
Nacos Config 通过适配 Spring Boot 的 ConfigData 接口实现无缝集成,核心步骤如下:
资源定义(ConfigDataResource)
Nacos 的配置资源通过NacosConfigResource封装,包含以下元数据: • Data ID:配置唯一标识(如nacos-config-dev.yml) • Group:配置分组(默认从 Nacos 配置读取DEFAULT_GROUP) • Namespace:多租户隔离标识(默认从 Nacos 配置读取) • 动态参数:如group(分组),refreshEnabled(是否启用刷新),preference(是否启用刷新),suffix(文件后缀)资源解析(ConfigDataLocationResolver)
Nacos 的解析器NacosConfigDataLocationResolver处理以下场景: • 标准格式解析:根据
spring.cloud.nacos.config参数生成 Data ID(格式:{prefix}-{profile}.{file-extension}) • 显式导入:支持通过
spring.config.import=nacos:dataId,group直接指定配置源
提示
Nacos 官网及文档很少提及但代码支持的方式:
例如配置如下:spring.config.import: nacos:example-config?group=test&suffix=.yml
此时会 NacosConfigDataLocationResolver 解析将此配置解析为 URI 格式,随后将路径参数解析到 NacosConfigResource.NacosItemConfig 的元数据中。路径参数优先级高于 spring.cloud.nacos.config。
- 配置加载(ConfigDataLoader)
Nacos 的加载器NacosConfigDataLoader实现以下逻辑: • 远程拉取:
通过ConfigService调用 Nacos Server 的 HTTP API 获取配置内容
Nacos Share Config 实现简介
从前文可知,Nacos Config 是基于 Spring Boot 的 ConfigData 机制实现的,最终通过 ConfigService 加载配置。
因此我们可以通过实现 ConfigData 机制和自定义 ConfigService 来实现跨命名空间的配置加载逻辑。
核心类及用于如下:
- NacosShareConfigService:Nacos 默认
ConfigService为命名空间强隔离,一个应用程序也仅有一个ConfigService实例,因此需扩展ConfigService支持多命名空间配置加载。 - NacosShareConfigManager:Nacos 通过全局对象
NacosConfigManager来持有ConfigService,并且它通过全路径类名加载ConfigService,因此需自定义。 - NacosShareConfigDataLocationResolver: Nacos 在
NacosConfigDataLocationResolver初始化NacosConfigManager及 Nacos 配置,因此需复写此逻辑,将修改后的NacosShareConfigManager注入到 Spring Bootstrap Context 中。
此时,Nacos Share Config 实现的核心逻辑已完成。
因 Nacos Config 相关自动配置均使用 NacosConfigManager 来获取 ConfigService,相关的依赖有
com.alibaba.cloud:spring-alibaba-nacos-config: ConfigData 接口实现,Nacos 刷新及 Client 管理等com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:Nacos 配置刷新监听及 Spring 配置刷新管理、单配置文件刷新扩展功能等
