Skip to content

Nacos 配置中心

This content is not available in your language yet.

单体应用里,配置跟着代码一起发布。进入多环境、多实例部署后,数据库地址、功能开关、限流阈值等配置必须独立管理。

配置中心不只是”把配置存到另一台服务器”,还要解决多环境隔离秒级发布动态推送故障回退

Feat Cloud 没有内置 Nacos starter。 本文直接使用官方 nacos-client,不额外封装。多写几十行胶水代码,换来的是完全透明的链路——连接在哪建立、配置在哪回调、坏配置为什么被拦截,全部一目了然。

在已有 Feat Cloud 应用基础上,加上 nacos-client

pom.xml
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>3.2.3</version>
</dependency>

nacos-client 是运行期依赖,feat-cloud-starter 仍然负责编译期生成代码。两者各管各的,互不替代。

Nacos 服务地址、namespace、鉴权信息这类”环境之间会变、但启动后不变”的参数,放进 feat.yml 最合适。

feat.yml
nacos:
serverAddr: 127.0.0.1:8848
namespace: public
username: nacos
password: nacos

这些值会在编译期通过 @Value 解析并注入到字段里。因为 @Value 只支持 StringintString[]List<String> 等少量类型,所以 Nacos 连接参数统一用字符串声明最省事。

本地开发连本机 Nacos,测试环境连测试集群,生产环境连生产集群。这是典型的 Profile 场景。

feat-dev.yml
nacos:
serverAddr: dev-nacos.example.com:8848
namespace: dev
feat-prod.yml
nacos:
serverAddr: prod-nacos.example.com:8848
namespace: prod

不同环境各有一套 FeatApplication* 生成类,启动时通过 feat.profiles.active 选择:

选择生产环境启动
java -Dfeat.profiles.active=prod -jar yourapp.jar

配置中心最核心的需求不是”能读到配置”,而是”配置变更时应用能安全地用上新值”。下面用一个类完成连接、拉取和监听,保持最小结构。

NacosConfigService.java
package com.example.nacos.config;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import tech.smartboot.feat.cloud.annotation.*;
import java.util.Properties;
import java.util.concurrent.Executor;
@Bean(order = 0)
public class NacosConfigService {
@Value("${nacos.serverAddr}")
private String serverAddr;
@Value("${nacos.namespace:public}")
private String namespace;
@Value("${nacos.username:}")
private String username;
@Value("${nacos.password:}")
private String password;
private static final String DATA_ID = "demo-config";
private static final String GROUP = "feat";
private ConfigService configService;
private String config;
@PostConstruct
public void init() throws Exception {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
if (username != null && !username.isEmpty()) {
properties.put(PropertyKeyConst.USERNAME, username);
properties.put(PropertyKeyConst.PASSWORD, password);
}
configService = NacosFactory.createConfigService(properties);
// 一次调用完成"拉取初始配置 + 注册监听器",避免拉取与注册之间的空窗期
config = configService.getConfigAndSignListener(DATA_ID, GROUP, 3000, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
if (configInfo != null) {
config = configInfo;
}
}
});
}
public String getConfig() {
return config;
}
@PreDestroy
public void close() throws Exception {
if (configService != null) {
configService.shutDown();
}
}
// setter
public void setServerAddr(String serverAddr) { this.serverAddr = serverAddr; }
public void setNamespace(String namespace) { this.namespace = namespace; }
public void setUsername(String username) { this.username = username; }
public void setPassword(String password) { this.password = password; }
}

这段代码做了四件事:

  1. 建立连接:用 nacos.serverAddr 等参数创建 ConfigService
  2. 拉取 + 监听:通过 getConfigAndSignListener 一次调用拿到初始值并注册监听器,省去先 getConfigaddListener 的两步操作,也避免两者之间的空窗期
  3. 优雅关闭:应用停机时断开长连接

写一个简单的接口,验证配置能读到、刷新也生效。

DemoController.java
package com.example.nacos.controller;
import com.example.nacos.config.NacosConfigService;
import tech.smartboot.feat.cloud.RestResult;
import tech.smartboot.feat.cloud.annotation.*;
@Controller("config")
public class DemoController {
@Autowired
private NacosConfigService nacosConfigService;
@RequestMapping("/current")
public RestResult<String> current() {
return RestResult.ok(nacosConfigService.getConfig());
}
}

启动应用后:

验证配置读取
curl http://localhost:8080/config/current

然后去 Nacos 控制台修改 demo-config / feat 这个配置的内容,稍等片刻再请求一次,应该能看到新值。

上线前记住三件事就够了:

  • 开鉴权:Nacos 服务端开启鉴权,口令不要写死在仓库里
  • 先校验再刷新:监听到新配置后先检查格式和必填字段,坏配置不要覆盖内存值
  • 先初始化基础设施NacosConfigService 这种 Bean 的 order 设为 0,让它先于默认 Bean 初始化

这三条基本就覆盖了大多数生产问题。

把上面的代码拼起来,你应该能验证下面这条链路:

Nacos 配置中心 -> NacosConfigService -> DemoController -> /config/current

可以用这些命令验证:

配置中心验证
curl http://localhost:8080/config/current
# 修改 Nacos 里的 demo-config / feat,等待 1-3 秒后再请求
curl http://localhost:8080/config/current

如果两次请求分别返回修改前后的配置内容,说明 Nacos 配置中心已经成功接入了。

Feat 不包一层 starter,也不重写配置中心。Nacos 的 ConfigService、Listener、长轮询全是官方原生的东西;Feat 只负责把它接进生命周期:编译期注入、启动时初始化、停机时释放。

多写几十行胶水代码,换来的是每一行都看得见——连接在哪建立、配置在哪回调、坏配置为什么被拦截。排查线上问题时,你能立刻定位是 Feat 的生命周期、Nacos 客户端,还是配置内容本身出了问题。

接 Sentinel、Redis、RocketMQ 时,套路一样:依赖 + @Value + @PostConstruct + @PreDestroy,中间按官方文档来。