Spring Cloud Alibaba Nacos Config 是如何读取配置的?

nacos 配置最高级别的隔离是 namespace,其后是 group;如果有配置隔离的诉求,建议优先使用 namespace 进行隔离。因为对于 sharedConfigs 和 extensionConfigs 来说,他们使用的是默认的 DEFALUT_GROUP,所以如果你配置了 sharedConfigs 和 extensionConfigs ,期望通过指定 group 进行隔离是做不到的。

本文主要分析 Spring Cloud Alibaba Nacos 配置客户端读取配置的部分过程,逻辑入口是 com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate;通过本篇,

  • 1、了解到 sharedConfigs、extensionConfigs 如何加载
  • 2、应用配置加载时,dataId 的计算逻辑
  • 3、如何通过 group 和 namespace 来隔离配置
  • 4、如何禁用默认的 DEFAULT_GROUP

加载顺序和 sharedConfigs、extensionConfigs 加载逻辑

这里的配置主要指的是 sharedConfigs、extensionConfigs 以及用户通过 namespace+group+dataId 指定的应用配置。

加载顺序

1
2
3
4
5
6
7
8
9
// 配置临时存档的地方
CompositePropertySource composite = new CompositePropertySource(
NACOS_PROPERTY_SOURCE_NAME);
// 1、先加载 sharedConfigs
loadSharedConfiguration(composite);‘
// 2、接着加载 extensionConfigs
loadExtConfiguration(composite);
// 最后加载指定的应用配置
loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);

这里除了需要关注顺序之后,还有一点非常重要,就是对于 sharedConfigs、extensionConfigs 两个指定的配置,他们不依赖用户指定的 group,而是使用默认的 DEFAULT_GROUP,下面来看。

sharedConfigs 加载逻辑

先通过代码大概理解下逻辑

1
2
3
4
5
6
7
8
9
10
11
private void loadSharedConfiguration(
CompositePropertySource compositePropertySource) {
// 通过配置获取 sharedConfigs 列表
List<NacosConfigProperties.Config> sharedConfigs = nacosConfigProperties
.getSharedConfigs();
// 如果没有配置,则啥都不做
if (!CollectionUtils.isEmpty(sharedConfigs)) {
checkConfiguration(sharedConfigs, "shared-configs");
loadNacosConfiguration(compositePropertySource, sharedConfigs);
}
}

假设我通过 sharedConfigs 指定的配置如下:

1
2
3
4
5
6
7
spring.cloud.nacos.config.shared-configs=
application.yaml,
application.properties,
application-staging.yaml,
application-staging.properties,
application-CN.properties,
application-staging_CN2.properties

通过 debug 面板看到,对于指定的 sharedConfigs,全部都挂在 DEFALUT_GROUP 下。

image-20220303212133294.png

不管是 sharedConfigs 还是 extensionConfigs,抑或是用户指定 group 的配置,nacos 在读取配置时,都是优先从本地开始读,如果本地没有,才从远端配置服务端去读取。

spring.cloud.nacos.config.extension-config 配置加载和 sharedConfigs 基本一致,这里不展开介绍。

应用配置加载逻辑中的 dataId 计算

这里主要指的是加载用户指定的 group 情况下的应用配置加载,还是先通过代码看下基本逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void loadApplicationConfiguration(
CompositePropertySource compositePropertySource, String dataIdPrefix,
NacosConfigProperties properties, Environment environment) {
// 先获取文件的后缀名,比如 yml ,properties
String fileExtension = properties.getFileExtension();
// 获取 group
String nacosGroup = properties.getGroup();
// load directly once by default
loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
fileExtension, true);
// load with suffix, which have a higher priority than the default
loadNacosDataIfPresent(compositePropertySource,
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
// Loaded with profile, which have a higher priority than the suffix
for (String profile : environment.getActiveProfiles()) {
String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
fileExtension, true);
}
}

上面代码片段中,加载配置有三种,第一是直接加载,这里的 dataId 使用的是 dataIdPrefix;第二是通过指定后缀加载;最后是通过 指定的 profile 加载。假设 spring.application.name 为 login-service,fileExtension 是 yaml, profile 为 staging,test,下面看下 dataId 的计算。

直接加载

第一部分是加载默认的,这里的默认指的是 dataId 为 dataIdPrefix,dataIdPrefix 可以通过 spring.cloud.nacos.config.prefix 配置,如果没有配置,则使用的是 spring.application.name;这里去加载时,会有从本地文件先加载的逻辑,以这种情况为例,Mac 下本地路径为:

1
 /Users/xxx/nacos/config/xxx/data/config-data-tenant/{namespace}/{group}/{dataId}

如果本地没有,那就根据 namespace, group 和 dataId 去 nacos 服务端去获取,在直接加载这部分。

使用指定的 suffix 加载

ns 和 group 都没变,但是 dataId 变成了 dataIdPrefix + DOT + fileExtension,所以 dataId 就变成了 login-service.yaml,其他加载逻辑和第一部分保持一致。

使用指定的 profile

从代码可以看到,如果指定了多个 profile,则会遍历所有 profile 然后拼接 dataId;这里 dataId 的计算逻辑是 dataIdPrefix + SEP1 + profile + DOT + fileExtension;比如 dataIdPrefix 是 login-service,profile 是 staging,fileExtension 是 yaml,那么得到的 dataId 就是 login-service-staging.yaml,然后在根据 ns、group 和这个计算出来的 dataId 去 nacos 服务端拉去配置,其他逻辑和前面加载配置逻辑一致。

配置加载过程

1、优先使用本地配,代码逻辑在

com.alibaba.nacos.client.config.NacosConfigService#getConfigInner

1
2
// 优先使用本地配置
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);

image.png

2、配置资源定位

配置资源定位通过三个参数 namespace + group + dataId 来确定

image-20220303213229747.png

从远端拉去之后,会优先创建本地快照,便于下次加载时能够优先从本地加载到

3、文件格式解析
上一步拿到的data,原始数据是字符串类型,然后会根据配置的后缀名,来匹配一个 loader 解析器,nacos 中提供了 4 种类型的解析器

image-20220303213733933.png

通过解析器将 string 类型的数据进行处理,然后放到 propertySource,这些 propertySource 会被放在 NACOS_PROPERTY_SOURCE_REPOSITORY 这个 ma p 结构中,ke y 为 dataId,group

image-20220303214150471.png

小结

nacos 配置最高级别的隔离是 namespace,其后是 group;如果有配置隔离的诉求,建议优先使用 namespace 进行隔离。因为对于 sharedConfigs 和 extensionConfigs 来说,他们使用的是默认的 DEFALUT_GROUP,所以如果你配置了 sharedConfigs 和 extensionConfigs ,期望通过指定 group 进行隔离是做不到的。

Spring Cloud Alibaba Nacos Config 是如何读取配置的?

http://www.glmapper.com/2022/03/13/springcloud/spring-cloud-config-nacos-config-locator/

作者

卫恒

发布于

2022-03-13

更新于

2022-04-24

许可协议

评论