前言
Nacos 不仅仅可以作为注册中心来使用,同时它也支持作为配置中心,在 Nacos 中支持配置的优先级,本文在从源码角度来看待它们是如何按顺序优先加载的
基础配置
接下来演示一下如何使用 Nacos 配置,首先新建 Module:alibaba-vnjohn-3377
pom 文件
旧版本
spring-cloud 旧版本只需要引入一个 nacos-config 依赖即可.
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.2.9.RELEASE</version> </dependency>
新版本
官方文档:Spring Cloud 2021.0.1.0 版本升级指南
从 2021.0.1.0 开始,SCA 版本将会对应 Spring Cloud 版本, 前三位为 Spring Cloud 版本,最后一位为扩展版本,升级版本 (注意版本对应关系) 父模块引入依赖:
<properties> <java.version>1.8</java.version> <spring-boot-version>2.6.7</spring-boot-version> <spring-cloud-version>2021.0.1</spring-cloud-version> <spring-cloud-alibaba-version>2021.0.1.0</spring-cloud-alibaba-version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot-version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud-version}</version> <type>pom</type> <scope>import</scope> </dependency> <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> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> </dependencyManagement>
注意事项:spring-cloud-starter-alibaba-nacos-config
模块移除了 spring-cloud-starter-bootstrap
依赖,如果你想以旧版的方式使用,你需要手动加上该依赖,现在推荐使用 spring.config.import
方式引入配置
官方解释:抛弃 bootstrap 引入配置的方式,使用
spring.config.import
方式引入配置,spring boot 2.4 对这一块做了很大的优化工作,不再需要全量启动一个容器来刷新配置
本文还是以以前的方式为例,引入 spring-cloud-starter-bootstrap
依赖,若不引入这依赖,在启动时就会出现无法解析配置参数
子模块依赖引入:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> </dependencies>
YML 配置
在这里要配置两个,因为 Nacos 和 spring-cloud-config 一样,在项目初始化时,要保证先从配置中心进行拉取,拉取完配置以后,才能保证项目正常启动
SpringBoot 中配置文件加载是存在于优先级顺序的,优先级:application < bootstrap,这两个分别要配置的是:
application.yml
spring: profiles: # 开发环境 active: dev
bootstrap.yml
server: port: 3377 spring: application: name: cloud-3377 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 file-extension: yaml namespace: 5040e7c3-c54e-4d3d-908e-70d1f2159097 # 这代表的是 dev 命名空间Id值
启动类
// 与之前的没有什么变化 @SpringBootApplication @EnableDiscoveryClient public class Cloud3377Application { public static void main(String[] args) { SpringApplication.run(Cloud3377Application.class, args); } }
控制器类
实现配置自动更新,语义:使配置文件中的配置信息修改以后无需进行重启,即可使用到修改后的值,就可以通过 @RefreshScope 注解来实现
/** * @author vnjohn * @since 2023/2/22 */ @RefreshScope @RestController public class CloudAppController { @Value("${cloud.name}") private String cloudName; @GetMapping("/cloud") public String cloud() { return cloudName; } }
若配置了以下属性值,即使加了注解也不会生效的
spring: cloud: nacos: config: refresh-enabled: false
配置规则
简介
在 Nacos Spring Cloud 中,dataId
的完整格式如下:
${prefix}-${spring.profiles.active}.${file-extension}
prefix
默认为spring.application.name
的值,也可以通过配置项spring.cloud.nacos.config.prefix
来配置spring.profiles.active
即为当前环境对应的 profile,注意:当spring.profiles.active
为空时,对应的连接符-
也将不存在,dataId 的拼接格式变成${prefix}.${file-extension}
file-exetension
为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension
来配置,目前只支持properties
和yaml
类型- 通过 Spring Cloud 原生注解
@RefreshScope
实现配置自动更新 - 通过官方给出的规则我们最终需要在 Nacos 配置中心添加的配置文件的名字规则和名字为:
# ${spring.application.name}-${spring.profiles.active}.${file-extension} # cloud-3377-dev.yaml # 微服务名称-当前环境-文件格式
- 不过即使配置文件名字不拼接
spring.profiles.active
,Nacos 默认也会帮我们加载cloud-3377.yaml
文件的配置,具体原因可以看后面的源码讲解.
实现不同环境之间的隔离,不一定要通过spring.profiles.active
区分,我们可以通过 Nacos 不同的命名空间来区分,比如:dev-开发环境、test-测试环境、prod-生产环境
自动配置更新&测试
首先在 dev 命名空间下新增 dataId 名为 cloud-3377 文件,文件内容如下:
config: info: I'm cloud-3377 version 1
按照上面给到的代码,访问接口:http://localhost:3377/config/info,得到的值:I’m cloud-3377 version 1
此时,再修改 dataId 文件的内容:I’m cloud-3377 version 2,进行发布,再访问接口地址,得到的值:I’m cloud-3377 version 2
不同环境相同配置
在实际的开发中,项目中所用到的配置参数有时并不需要根据不同的环境来进行区分,开发、测试、生产所用到的参数是相同的,例如:端口号、应用名称;那么解决同一个服务在多个环境中,引用相同的配置问题?Nacos Config 也提供了相应的解决方案,也就是我上面说过的,即使不拼接 spring.profile.active
,Nacos 也会帮我们自动加载
在这里就可以通过服务名+扩展名方式,来实现同一个微服务下不同环境进行共享的配置文件
在 Nacos Config 中添加配置,dataId->cloud-3377.yaml
控制器代码调整:
/** * @author vnjohn * @since 2023/2/22 */ @RefreshScope @RestController public class CloudAppController { @Value("${cloud.name}") private String cloudName; @Value("${cloud.common}") private String cloudCommon; @GetMapping("/cloud") public String cloud() { return cloudName; } @GetMapping("/cloud/common") public String cloudCommon() { return cloudCommon; } }
访问接口:http://localhost:3377/cloud/common,读取配置
不同微服务如何共享配置
以上 不同环境使用相同配置
是最基础的配置方式,但我们在实际开发中一般会涉及到多个微服务之间共享配置;比如:redis 地址,服务注册中心公共组件等,那么这些组件是多个微服务共享的,所以我们可以使用 Nacos Config 提供的共享方式来配置共享的配置文件
在 Nacos 控制台中添加 common.yaml、redis.yaml
common.yaml 文件内容如下:
# 手机、邮箱正则表达式公共引入 phone: regex: ^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[013,5-8]|18[0-9]|19[189])[0-9]{8}$ email: regex: ^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}$
common-redis.yaml 文件内容如下:
redis: ip: 127.0.0.1 port: 6379
通过 shared-configs 参数进行配置引入 common.yaml
配置,调整内容如下:
spring: application: name: cloud-3377 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 file-extension: yaml namespace: 5040e7c3-c54e-4d3d-908e-70d1f2159097 shared-configs: - dataId: common.yaml refresh: true # 默认值为 false,不开启自动刷新,要搭配 @RefreshScope 注解一起使用 group: DEFAULT_GROUP # 默认分组名:DEFAULT_GROUP,可以不写 # - 可以继续追加
以上通过了 -
进行了配置,也可以这样进行配置:shared-configs[0].dataId、shared-configs[0].refresh,这样写只是更加美观,在配置多个的情况下能更加清晰的明白.
除了 shared-configs 进行配置,还可以通过 extension-configs
配置,配置方式和其一样,只是换了个名字,语义上更好的区分出了一个微服务有扩展配置的情况,配置 common-redis.yaml 内容如下:
spring: application: name: cloud-3377 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 file-extension: yaml namespace: 5040e7c3-c54e-4d3d-908e-70d1f2159097 shared-configs: - dataId: common.yaml refresh: true # 默认值为 false,不开启自动刷新,要搭配 @RefreshScope 注解一起使用 group: DEFAULT_GROUP # 默认分组名:DEFAULT_GROUP,可以不写 extension-configs: - dataId: common-redis.yaml refresh: true # - 可以继续追加
从以上可以看到,这些共享配置、扩展配置也是支持配置自动刷新机制的,但它们默认是不会开启自动刷新的,若在实际业务中需要对共享或扩展配置的内容进行热部署取值,可以进行配置
整体配置优先级
Spring Cloud Alibaba Nacos Config 提供了三种配置能力从 Nacos 拉取相关的配置
A:通过 spring.cloud.nacos.config.shared-configs[n].data-id
方式支持多个共享 dataId 配置
B:通过 spring.cloud.nacos.config.extension-configs[n]-data-id
方式支持多个扩展 dataId 配置
C:通过内部相关规则(应用名、应用名+Profile)自动生成相关的 dataId 配置
当三种方式同时使用时,它们的优先级关系:A < B < C,同理,若在这三种方式中配置了同样的参数时,则会使用 C 配置的参数值
总结
该篇博文讲解在实际工作如何使用 Nacos 、配置动态刷新的运用,对 Spring Cloud 新老版本的依赖引入作了描述,从 2021.0.1.0 版本开始,移除了 spring-cloud-starter-bootstrap 依赖,最后,对配置的优先级作了区分,对不同环境配置、不同微服务如何共享配置做了详细的介绍,下篇文章让我们从源码的角度来看 Nacos 是如何加载配置的!
如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!
推荐专栏:Spring、MySQL,订阅一波不再迷路
大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!