楼层: 首页/ 软件技术/ Spring Cloud 微服务/ 配置中心:Nacos Config
三

配置中心:Nacos Config

Centralized Configuration with Nacos

第二个灵魂拷问:100 个服务改个日志级别,要改 100 个文件再重启 100 次?单体里配置写在 application.yml 里,简单粗暴。微服务时代,每个服务一份配置,数据库密码改一次要翻 50 个仓库。配置中心就是把所有配置集中到 Nacos 上,改一处、秒推所有服务。

论Nacos Config 的三个核心概念

Namespace:还是那个命名空间,配置也按 dev/test/prod 隔离。

Group:同一环境里的业务分组,不分组也行,默认 DEFAULT_GROUP。

Data ID:配置文件的唯一名字。Nacos 找一份配置靠的就是 Data ID。默认规则是 ${spring.application.name}-${spring.profiles.active}.${file-extension},比如 user-service-dev.yaml。

动态刷新:配置改了,加了 @RefreshScope 注解的 Bean 会自动拿到新值,不用重启服务。这是配置中心最爽的地方。

接入 Nacos Config:bootstrap 配置

Spring Boot 3.x 之后,bootstrap.yml 默认不加载了,需要额外引入 spring-cloud-starter-bootstrap,或者直接在 application.yml 里配。新项目推荐后者。下面给一个能跑的写法。

pom.xml 里加配置中心依赖

<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>

application.yml:告诉 Spring 启动时去 Nacos 拉配置

spring: application: name: user-service profiles: active: dev # 决定加载 user-service-dev.yaml 这份配置 cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml # 配置文件格式,可选 properties / yaml namespace: dev # 从哪个命名空间拉 group: DEFAULT_GROUP config: import: "nacos:user-service-dev.yaml" # Spring Boot 2.4+ 推荐写法

业务代码里用 @Value 注入配置,并加 @RefreshScope 实现热刷新

import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/user") @RefreshScope // 关键!不加这个,Nacos 上配置改了这里拿不到新值 public class UserController { // 从 Nacos 配置里读 "user.welcome" 这个值,没配就给默认值 "你好" @Value("${user.welcome:你好}") private String welcome; @GetMapping("/welcome") public String welcome() { return welcome; // Nacos 上改了这个值,下一次请求就是新的 } }
配置优先级,别搞反了

很多人奇怪"我 Nacos 上明明配了,怎么不生效?"——多半是本地 application.yml 把 Nacos 的值覆盖了。Spring Boot 配置优先级里,命令行参数 > 环境变量 > Nacos 远程配置 > 本地 application.yml(具体以官方文档为准)。也就是说,本地配置优先级更低,通常不会覆盖 Nacos;但如果你用了 --spring.config.import 或 profile 写死,就可能出问题。排错时先看启动日志里 Nacos Config 是不是真的拉到了配置。

配置优先级一张表

Spring Boot 配置有个优先级问题——同一个 key,从多个地方读到时以谁为准。数字越小优先级越高(覆盖别人),具体以 Spring Boot 官方文档为准:

优先级来源
1(最高)命令行参数(--user.welcome=xxx)
2操作系统环境变量、系统属性
3Nacos 远程配置(通过 spring.config.import 引入)
4本地 application.yml / application-{profile}.yml
5(最低)代码里的默认值(@Value("${x:默认值}"))

所以想让 Nacos 配置生效,别在本地 application.yml 里写同一个 key——本地会按上面优先级跟你抢。本地只放"连 Nacos 必须的"配置(server-addr、namespace),业务配置全放 Nacos。

灰度发布:让新版本配置先跑在几台机器上

改配置最怕一把全量推出去,结果配错了全站崩。Nacos 支持"灰度发布"——先把新配置推给指定的几台机器(按 IP 或元数据挑),观察没问题再全量。控制台里选"灰度"即可,代码不用改。学习阶段知道有这功能就行,生产环境是救命用的。

完整案例:两个微服务 + Nacos 注册发现 + 配置热刷新

光看概念没劲,跑一遍才懂。我们搭两个服务:order-service(订单)和 user-service(用户),都注册到 Nacos;user-service 读 Nacos 上的一句欢迎语,用 @RefreshScope 实现改配置不重启。

第一步:起 Nacos,控制台建配置

# 起单机 Nacos sh startup.sh -m standalone # 浏览器开 http://localhost:8848/nacos 账号 nacos/nacos # 控制台 → 配置管理 → 配置列表 → 新建配置: # Data ID: user-service-dev.yaml # Group: DEFAULT_GROUP # 格式: yaml # 内容: # user: # welcome: 你好,来自 Nacos 的第一条配置

第二步:user-service 的 application.yml(连注册中心 + 拉远程配置)

server: port: 8081 spring: application: name: user-service profiles: active: dev cloud: nacos: discovery: server-addr: localhost:8848 # 注册中心 config: server-addr: localhost:8848 # 配置中心,跟注册是同一个 Nacos file-extension: yaml config: import: "nacos:user-service-dev.yaml" # 启动时拉这份配置

第三步:user-service 控制器,@RefreshScope 实现热刷新

@RestController @RequestMapping("/user") @RefreshScope // 关键:Nacos 配置一变,这个 Bean 重新注入新值 public class UserController { @Value("${user.welcome:默认欢迎语}") private String welcome; @GetMapping("/welcome") public String welcome() { return welcome; } }

第四步:跑起来验证(不用重启!)

# 1. 启动 user-service,浏览器访问 # http://localhost:8081/user/welcome # 返回:你好,来自 Nacos 的第一条配置 # 2. 打开 Nacos 控制台,把 user.welcome 改成"第二条,热刷新了" # 点发布。控制台右下角会弹"监听长连接已收到配置变更" # 3. 立刻再访问 http://localhost:8081/user/welcome # 返回:第二条,热刷新了 ← 没重启!这就是 @RefreshScope 的魔力 # 4. 控制台 → 服务管理 → 服务列表,能看到 user-service 已注册 # 再起一个 order-service,同样在列表里出现,这就是服务发现

论注册发现 + 配置热刷新,到底干了啥

注册:user-service 启动时把自己的 IP:端口 报给 Nacos。

发现:order-service 要调 user-service,不写死 IP,按名字 user-service 问 Nacos 要地址。

热刷新:Nacos 配置一变,通过长连接推给所有监听的服务,带 @RefreshScope 的 Bean 自动重建、拿到新值。

@RefreshScope 不生效?两个检查点

① 忘了加 @RefreshScope——普通 Bean 注入一次就固定,必须加注解才会响应刷新。② 配置没真的拉到——看启动日志有没有 Located property source: [Nacos],没有就是 spring.config.import 或 Data ID 写错了。