Nacos 配置监听与动态刷新
配置中心的魅力在于"改了不用重启"。本章先讲客户端为什么能秒级感知,再给原生监听与 Spring 场景的示例。
秒级感知的原理:长轮询
客户端并不是每 5 秒轮询一次,而是与服务端保持长轮询:
- 客户端发请求:我关注的这几个 dataId,内容变了吗?
- 服务端比对每个 dataId 的内容签名(如 MD5):有变化,立即把变更的 dataId 返回
- 没变化,请求先"挂"在服务端不返回(约 30 秒超时),期间一旦有人发布配置,立即应答
2.x 中该交互走 gRPC 长连接,端到端延迟通常在秒级甚至更低,这就是"发布即生效"的来源。
原生监听:addListener(Java)
不引入 Spring 时,给某个 dataId 挂监听,配置一变就回调:
// 需放入 main 方法运行,并捕获 NacosException
Properties props = new Properties();
props.put("serverAddr", "localhost:8848");
ConfigService cs = NacosFactory.createConfigService(props);
cs.addListener("order-service.properties", "DEFAULT_GROUP", new Listener() {
@Override
public Executor getExecutor() {
return null; // 返回 null 表示用服务端默认线程池执行回调
}
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("收到新配置:" + configInfo);
// 输出:收到新配置:timeout=8000 (在控制台发布新值后触发)
}
});
Thread.sleep(Long.MAX_VALUE); // 保持进程存活,等待后续变更推送
回调里拿到的 configInfo 是变更后的完整配置文本,业务自行解析并应用。
Spring 场景:@RefreshScope 自动刷新
Spring 项目里给 Bean 加 @RefreshScope,配置一变容器就重建该 Bean,@Value 注入的新值立即生效(以下代码需放入 Spring 工程):
@RefreshScope
@Component
public class OrderTimeout {
@Value("${timeout:5000}") // 冒号后是默认值
private int timeout;
public int getTimeout() { return timeout; }
}
在控制台把 order-service.properties 里的 timeout 改成 8000 并发布,无需重启,下次读到的新值就是 8000。若使用非 Spring 标准的注入方式,可改用 Nacos 的 @NacosValue(..., autoRefreshed = true) 达到同样效果。
多实例推送的先后
一个服务有多个实例时,每个实例各自长轮询,推送存在先后:短时间内可能出现"部分实例已是新值、部分还是旧值",属于最终一致。因此重要配置建议在业务低峰发布,发布后观察一段时间再继续,而不是把 30 台实例的生效时间差当成故障。
内容校验与格式
配置按 dataId 后缀解析:.properties 按 properties 解析,.yaml 按 YAML 解析。内容不合法时,客户端解析可能报错或读不到预期值,建议:
- 发布前用对应格式工具本地校验一遍
- 先在测试环境发布验证,再发布生产
- 出问题用历史版本一键回滚(第 7 章)
小结
动态刷新的链路是:发布 → 服务端比对内容签名 → 长轮询命中立即返回 → 客户端 addListener 回调或 Spring 的 @RefreshScope 重建 Bean。理解"长轮询 + 内容比对"这个机制,就能解释为什么 Nacos 配置能做到秒级生效、以及多实例为何会有短暂不一致。