最近公司要搭建一个配置中心,由于不想自己运维,便选择了云服务,定的是阿里云的nacos服务,即 https://mse.console.aliyun.com/。

这里记录一下在springboot 2项目中,使用云nacos来做一些基本配置String、int等,和配置json数据映射到java对象中。

1 云nacos操作说明

在控制台创建一个实例,这个实例就是一个nacos的服务端。

在创建时,需要注意公网ip的问题,如果没有公网ip,就只能在阿里云服务器上才能访问,本地测试的话访问不了。

如图,基本信息里有公网、内网连接地址、端口信息。因为本篇是在本地使用云nacos,所以我在创建nacos时选择了外网地址。红框里需要 注意配置白名单,不在白名单里的ip无法访问云nacos。 本机的话,就在百度搜索ip,查看自己的外网ip,配进去如11.11.11.11/32即可。

当然配白名单麻烦,建议采用accessKey的方式访问配置中心,也就是把公网白名单删掉,把权限验证打开。然后用access-key和secret-key来访问nacos。

之后就可以创建配置了。

这里我没有创建命名空间,就默认是public的命名空间。

创建配置时,Group里填写名字,建议一个模块、一个应用用同一个Group,代表一个组。

Data ID的范围比Group要小,代表一个类型、一个对象,譬如我把系统里所有的开关都放到一个Data Id里,里面配很多个开关。譬如我可以把一个大对象,有多个属性,也作为一个Data ID。

将来监听变化,自动拉取最新配置信息的最小单元就是Data ID。

如图配置格式选择TEXT,就是最简单的类型,配置内容里就可以是a=1,b=2这种。这里面的每一行都是一个最小的配置项,将来代码里用的就是最小的配置项。

2 java接入云nacos

nacos提供了支持java、springboot的pom依赖,我们先来看看普通的java接入方式。

依赖的pom就不贴了,直接看使用的代码。

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 * @author weifengwu
 * @create 2023/9/4 15:48
public class NacosTest {
    public static void main(String[] args) {
        try {
            ExecutorService executorService = Executors.newFixedThreadPool(5);
            //改成自己的配置外网地址
            String serverAddr = "mse-xxxxxxx-p.nacos-ans.mse.aliyuncs.com:8848";
            Properties properties = new Properties();
            properties.put("serverAddr", serverAddr);
            //所有对于配置项的操作都是靠ConfigService完成的
            ConfigService configService = NacosFactory.createConfigService(properties);
            //读取该dataId的内容。注意,每次调用getConfig都会发起一次网络请求
            String content = configService.getConfig( "switch", "llmCenter", 5000);
            System.out.println(content);
            //读取一个配置项,该配置项是个json字符串,
            //  "app-pc-lu": {
            //        "userAudit": 1,
            //        "aiAudit": 14,
            //        "modelList": [
            //            "modelA",
            //            "modelB",
            //            "modelC"
            //        ]
            //    }
            String jsonAppFlowInfo = configService.getConfig("jsonAppFlowInfo", "llmCenter", 1000);
            //给这个Data ID添加一个监听器,当DataId数据发生变化时,会调用该回调方法。用户可以接收到新值后保存到内存里。
            configService.addListener("jsonAppFlowInfo", "llmCenter", new Listener() {
                @Override
                public Executor getExecutor() {
                    return executorService;
                @Override
                public void receiveConfigInfo(String s) {
                    System.err.println(Thread.currentThread().getName());
                    System.out.println(s);
            System.out.println(jsonAppFlowInfo);
            try {
                Thread.sleep(100000000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            //新增一个配置,如果已存在该DataId,则会覆盖
//            boolean isPublishOk = false;
//            try {
//                isPublishOk = configService.publishConfig("second", "llmCenter", "content=1");
//            } catch (NacosException e) {
//                throw new RuntimeException(e);
//            }
//            System.out.println(isPublishOk);
        } catch (NacosException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();

以上代码展示了获取配置、新增/修改配置,监听配置的功能。

需要注意的是configService.getConfig读取配置信息时,每次都会发起一个网络请求,并不是从本地内存读取的,这一点和我的认知中的配置中心不太一样,如果说的不对,可以指正,因为我从nacos的后台看到确实在不断的请求。

3 springboot接入云nacos

如果使用的是springboot,nacos提供了一些自动化监听的功能,当服务端配置的值发生变更时,不需要客户端做处理,即可自动读取到新的配置内容。

@RestController
@NacosPropertySource(groupId = "llmCenter", dataId = "switch", autoRefreshed = true)
@NacosPropertySource(groupId = "llmCenter", dataId = "textInfo", autoRefreshed = true)
public class TestController {
    @Autowired
    private ConvMessageService convMessageService;
    @NacosValue(value = "${useLocalCache:false}",autoRefreshed = true)
    private boolean useLocalCache;
    @NacosValue(value = "${one:1}",autoRefreshed = true)
    private String one;
    @NacosValue(value = "${model.name.app-pc-luca.userAudit:2}",autoRefreshed = true)
    private String userAudit;
     * 这种写法不支持,将无法映射
    @NacosValue(value = "${model.name.app-pc-luca.modelList:2}",autoRefreshed = true)
    private List<String> modelList;
    @RequestMapping(value = "/get", method = GET)
    public boolean get() {
        System.out.println("useLocalCache-" + useLocalCache);
        System.out.println("one-" + one);
        System.out.println("userAudit-" + userAudit);
        System.out.println("modelList-" + modelList);
        return true;

其中NacosPropertySource注解加在一个被spring托管的类上即可,里面注明了dataId和groupId,代表这个dataId的配置值发生变化时会自动推送到被@NacosValue标注的属性上。

其中@NacosValue里只需要写最终配置的属性名即可,不需要再指定dataId,也就是对应下图的每一行里的key。

@NacosValue(value = "${useLocalCache:false}",autoRefreshed = true)这个里面useLocalCache:false代表如果配置中心里没找到useLocalCache这个key,就用false作为默认值。

application.yml配置如下:

nacos:
  config:
    server-addr: mse-80a0d732-p.nacos-ans.mse.aliyuncs.com:8848
    access-key: xx
    secret-key: xxx
    autoRefresh: true
    data-ids: switch,hello,textInfo
    group: llmCenter
    bootstrap:
      enable: true

其中需要注意的点是,yml里面要写data-ids,这里面写的data-ids是等同于在java类上加的@NacosPropertySource(groupId = "llmCenter", dataId = "switch", autoRefreshed = true)。二者功能相同。

如果你在yml里配置了data-ids,那么类上的可以不用写。个人建议是都写在yml文件里即可。

4 对于json类型的

@Data
@NacosConfigurationProperties(groupId = "group-abc", dataId = "dataId-abc", type = ConfigType.JSON, autoRefreshed = true)
@Configuration
public class SceneModelAbTestConfig {
     * KYE 场景ID
     * VALUE 对应的 ab实验ID
    private Map<String, String> sceneModelAbTestMap;

对应的配置如下:

{"sceneModelAbTestMap":{"1":"1806221812426252290"}}

对于复杂点的对象:

@Data
@NacosConfigurationProperties(groupId = "group-ddd", dataId = "business-111", type = ConfigType.JSON, autoRefreshed = true)
@Configuration
public class BusinessLLmCenterConfig {
    private GenerateAgentHead generateAgentHead;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class GenerateAgentHead {
        private Integer modelId;
        private String systemPrompt;
        private String config;

在nacos配置如

{"generateAgentHead":{

"modelId":145,

"systemPrompt":"aaaaaaaaaa",

"config":"xxxxx"

也可以用代码的方式。在配置中心里,配一个json,建议用一个data-id来存放,里面放个json字符串。要使用时,自己解析即可。

见第二段java接入云nacos里的代码,通过下面的方式,获取到json字符串,并监听这个data-id字符串。

正确做法应该是,在项目启动时,就拉取配置,并将结果保存到系统内存中,使用时从内存中获取。当监听到变化时,也更新内存中的json对象。不要每次都用configService.getConfig获取。

//读取一个配置项,该配置项是个json字符串,
            //  "app-pc-lu": {
            //        "userAudit": 1,
            //        "aiAudit": 14,
            //        "modelList": [
            //            "modelA",
            //            "modelB",
            //            "modelC"
            //        ]
            //    }
            String jsonAppFlowInfo = configService.getConfig("jsonAppFlowInfo", "llmCenter", 1000);
            //给这个Data ID添加一个监听器,当DataId数据发生变化时,会调用该回调方法。用户可以接收到新值后保存到内存里。
            configService.addListener("jsonAppFlowInfo", "llmCenter", new Listener() {
                @Override
                public Executor getExecutor() {
                    return executorService;
                @Override
                public void receiveConfigInfo(String s) {
                    System.err.println(Thread.currentThread().getName());
                    System.out.println(s);
            System.out.println(jsonAppFlowInfo);

4 对于yaml类型的

代码指明是type = ConfigType.YAML

@Data
@NacosConfigurationProperties(groupId = "mf-backend", dataId = "push", type = ConfigType.YAML, autoRefreshed = true)
@Configuration
public class PushConfig {
    private Ios ios;
    private Android android;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Ios {
        private Integer badge;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Android {
        private Long appKey;

nacos里按yml格式配置即可

在我业务开发中,需要在配置中心配置Json数据,返回给前端。因Nacos默认不支持Json格式配置,需要搭配监听器获取配置中心Json数据,返回给客户端。 二、搭配Nacos配置Josn数据 1. bootstrap.yml 具体使用 只需要 在 NacosConfig 中nacosConfigLocalCacheInfoMap方法添加对应配置映射即可,如下。默认不支持Json格式配置,需要搭配监听器获取配置中心Json数据,返回给客户端。Nacos配置代码: feign-demo→order-service-nacos。6. NacosConfigLocalCatch 核心监听触发类。在我业务开发中,需要在配置中心配置Json数据,返回给前端。二、搭配Nacos配置Josn数据。2. nacos配置-测试案例。 默认情况下sentinel dashboard中配置的规则是API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource),当服务重启或者重新部署后,配置的规则需要重新配置,不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 持久化数据到nacos中(Push模式) 生产环境下一般更常用的是 push 模式的数据源。对于 push 模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客户 上一篇我接入了rocketmq和redis,本次要接入的中间件是阿里的nacos,用于当做配置中心。关于nacos的安装可以参考我之前写过的docker 安装naocos的文件 nacos是阿里用于spring cloud体系下的一个突破吧,可以用作注册发现和配置中心,支持自动刷新配置,我个人更加喜欢他的自动刷新配置功能,比spring cloud 的config和bus的动态配置有更多用法。常见用法就是用于动态刷新配置。 举例:有一个项目由一个新功能上线。我也不确定这个功能是否好用,我需要及时 nacos是一个分布式配置中心,可用它做配置管理、服务发现等,目前用到它的是配置中心的功能在日常的web开发中常常会用到一些配置,如数据库连接地址、端口、账号、密码,jwt密钥等配置,如果是直接写在config配置文件中的话,等项目启动后再想变更配置参数会很麻烦,而且如果服务多的话修改起来也麻烦,所有需要一个配置中心记录配置信息,各个服务都从配置中心中拉取配置参数,后端服务做个长轮训监听配置中心的配置消息,如果有变动则更新服务中的配置。 //从配置文件获取机构允许创建的试听课次数 private Integer getAuditionLessonCount(Long platformId){ String config = nacosConfig.getConfig(“auditionLessonCount”); JSONObject object = JS... 但是 dataId的命名不一样 我理解为 aaa 这种 等于你创建了一个没有后缀的配置文件。本文用的是 Nacos作为配置中心注册监听器方法 实现热更新 nacos 配置文件。因为项目用的是 Json 类型配置文件。虽然打开里面的配置信息都是 json格式。所以下文 主要是对json文件进行实现。dataId 这两种声明 是不一样。依赖、工具类 这边就不写了。在nacos配置文件中。下面开始直接上实现代码。 这里写自定义目录标题 Nacos 使用 @NacosInjected无法获取到 ConfigService,访问接口时提示该注入类为null,导致我无法通过她的 String getConfig(String dataId, String group, long timeoutMs) throws NacosException; 这个方法获取json数据, 这是有问题的代码,看了十多分钟,最后翻开源码 可以清楚的看到这张图的类对象并没有让spring托管 根据启动时的debug找到了configSer