前言
配置中心,最早的时候用过360的QConf,后来又用过一阵子携程的Apollo,最近这2年用的都是阿里的Nacos。
QConf的技术路线独辟蹊径,之前在PHP的项目里用的很舒服。但毕竟不属于Java技术栈上的产品,后来Java团队技术选型的时候也就没再沿用它。写文章的时候看了一眼QConf的GitHub主页,最后一次更新还是2017年的时候了。
Nacos作为阿里云原生环境下的配置中心,应该是目前最有前途的配置中心了。Nacos基于阿里云庞大的用户群可以获取大量的反馈,产品也就能打磨的越来越好。
环境准备:
服务端
本机安装Nacos参考官网就好了,启动一个单机版的实例就够开发测试用了。阿里云托管的Nacos在阿里云的MSE板块下面。
客户端
全家桶的版本配置,参考这里的版本关系,选择的是Spring Boot 2.6的版本。版本的不同影响还挺大的,后面再细说。
<properties>
<spring-boot.version>2.6.13</spring-boot.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
</properties>
增加Nacos的依赖项:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
注意: 由于spring-cloud-starter-alibaba-nacos-config移除了spring-cloud-starter-bootstrap依赖。现在推荐使用 spring.config.import 方式引入配置。你在网上找到的大部分文章都在介绍怎么在bootstrap.yml里配置nacos,但是现在你需要换成application.yml了:
说一句题外话: 把配置文件统一成yml格式吧,不仅覆盖Properties格式的所有功能,结构还更清晰。
# application.yml
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: 5j@Tc3fbgeE@TRi
namespace: 075fc053-5a4e-4785-9f3d-638d86d76b1f
spring:
cloud:
nacos:
# 当nacos客户端的配置中nacos.core.auth.enabled=true时,username、password不能省略
username: ${nacos.username}
password: ${nacos.password}
config:
file-extension: yml
refresh-enabled: true
server-addr: ${nacos.server-addr}
namespace: ${nacos.namespace}
config:
import:
- optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}
最下面这行import就是引入nacos配置文件的,如果没有这一行会报错:
***************************
APPLICATION FAILED TO START
***************************
Description:
The spring.config.import property is missing a nacos: entry
Action:
Add a spring.config.import=nacos: property to your configuration.
If configuration is not required add spring.config.import=optional:nacos: instead.
To disable this check, set spring.cloud.nacos.config.import-check.enabled=false.
客户端动态获取配置中心的值
@RestController
@RequestMapping("/nacos-config")
@RefreshScope
public class NacosConfigController {
@Value("${welcome.message}")
private String welcomeMessage;
@GetMapping("/welcome")
public String showWelcome() {
return this.welcomeMessage;
}
}
使用@Value("${}")注解跟获取本地参数一样的方式获取远端配置中心的值。加上@RefreshScope注解保证配置可以实时更新
插播一段小插曲: 之前在测试的时候,我在Nacos的yml配置文件里设置的变量名正好是user.name。结果代码里获取的变量始终是登陆系统的用户名,不管怎么改Nacos配置甚至重启Nacos都不生效。倒腾好一阵子,才发现user.name是Java的系统变量,而且它的加载顺序是晚于配置文件的加载的,所以无论在Nacos里面怎么改,最后都会被系统变量所覆盖。
Nacos的几个概念
- Namespace
- Data ID
- Group
如果你在网上看过几篇介绍Nacos使用的文章,你肯定看到过类似这样的话:同一个应用在不同环境下的配置,通过namespace来做环境隔离。比如开发环境的namespace命名为dev,测试环境的namespace命名为test,线上环境的namespace命名为prod。
我不知道真正有多少公司是这样使用namespace的。在我工作过的环境里,测试环境和线上环境的网络都是不通的,更不会用一套配置中心来支持多个环境,而是测试环境是测试的Nacos集群,线上环境是线上的Nacos集群。应用通过启动参数spring.profiles.active=<profile>来指定使用不同的配置文件,进而连接到不同的集群。
我们把Namespace用来标志业务域。比如order,goods,passport这样。而Data ID,我们让它跟服务名称保持一样。至于Group,用的就是DEFAULT_GROUP,没改过。
一个容易踩坑的小点:配置文件里指定的Namespace,应该是你在Nacos控制台上看到的那个ID,也就是下图红框里的部分,而不是绿框里的。
至于在过去的版本里讨论的extension-configs,shared-configs的优先级和使用问题。貌似也不用过多的考(背)虑(诵)了。直接在spring.config.import里面一个个的往后加就完了
spring:
cloud:
nacos:
# 当nacos客户端的配置中nacos.core.auth.enabled=true时,username、password不能省略
username: ${nacos.username}
password: ${nacos.password}
config:
file-extension: yml
refresh-enabled: true
server-addr: ${nacos.server-addr}
namespace: ${nacos.namespace}
config:
import:
- optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}
- optional:nacos:mysql-config.yml?group=datasource
- optional:nacos:redis-config.yml?group=datasource&refreshEnabled=false