Java - 利用Nacos做一个动态开关配置功能

news2025/7/14 15:33:02

Java - 利用Nacos做一个动态开关配置功能

  • 前言
  • 一. Nacos配置类编写
  • 二. 测试
  • 三. 展望

前言

我公司里有一个Config配置功能(我相信这是很普遍的一个功能)。简单来说就是:

  • 将相关的键值对放到这个Config配置系统里面。
  • 代码里通过这个Config配置系统的相关API,根据对应的Key拿到配置的值。在进行逻辑操作。

那么这个有啥好处呢?

  1. 我们将我们的代码发布到生产环境,往往是需要一定的流程的。可能耗时比较长。而Config配置系统的发布则非常简单。页面上点一下即可。
  2. 假如我们有一个场景:一个新老接口的替换。那么我们可以在代码里面加一个“开关”,如果为T,走新接口,如果为F,则走老接口。那么当生产上新接口出现问题的时候,我们就可以通过改变Config配置系统中的开关值为F。这样就可以在不发布代码的情况下,动态地改变程序地运行逻辑。
  3. Config配置系统除了可以用作开关的功能以外。还有个重要的功能就如其名,配置系统,我们可以通过这个系统动态地设置相关配置。
  4. 开关同样支持分环境、分Group等操作。

自己最近也在复习微服务这块的知识。自然而然地用到了Nacos。那么Nacos不就是一个天生的配置系统吗?因此准备在其基础上稍微写个工具类,达到模拟Config配置系统的功能。

一. Nacos配置类编写

我们知道Nacos的加载需要几个属性:

  • server-addr:服务地址。
  • namespace:命名空间。
  • group:组的名称。

如图:
在这里插入图片描述

前提:你的application.yml或者bootstrap.yml文件里面有对应的配置。

1.我们先写一个配置类,自定义我们的名称ZKNacosProperties

@Data
@Component
@ConfigurationProperties(prefix = "kz.nacos")
public class ZKNacosProperties {
    private String fileName;
    private Long timeout;
}

对应的application.properties文件

kz.nacos.file-name=kz-service-config.properties
kz.nacos.timeout=3000

2.NacosConfig配置类:

@Configuration
public class NacosConfig {
    @Value("${spring.cloud.nacos.discovery.server-addr}")
    private String serverAddr;
    @Value("${spring.cloud.nacos.config.namespace}")
    private String namespace;
    @Value("${spring.application.name}")
    private String group;
    @Autowired
    private ThreadPoolExecutor executor;
    @Autowired
    private ZKNacosProperties zkNacosProperties;

    @Bean
    @RefreshScope
    public Map<String, String> zConfig() {
        HashMap<String, String> config = new HashMap<>();
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        properties.put(PropertyKeyConst.NAMESPACE, namespace);
        ConfigService configService;
        try {
            configService = NacosFactory.createConfigService(properties);
            addListener(configService, config);
            String content = configService.getConfig(zkNacosProperties.getFileName(), group, zkNacosProperties.getTimeout());
            updateCache(content, config);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return config;
    }

    /**
     * Nacos在项目启动的时候,就会将配置进行读取,并起了一个线程 LongPollingRunnable
     * 用于感应Nacos端的配置变换
     * 这里用我们自定义的线程池做替换
     *
     * @param configService
     */
    private void addListener(ConfigService configService, Map<String, String> config) {
        try {
            if (configService != null) {
                configService.addListener(zkNacosProperties.getFileName(), group, new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return executor;
                    }

                    @Override
                    public void receiveConfigInfo(String s) {
                    	// 更新我们的本地配置
                        updateCache(s, config);
                    }
                });
            }
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    private void updateCache(String content, Map<String, String> config) {
        if (StringUtils.isBlank(content)) {
            return;
        }
        String key, value;
        // 拿到的content是一个完整的内容,我们一般是一行一个配置。这里按照行来分割
        String[] configs = content.split("\n");
        for (String c : configs) {
            String[] keyValue = c.split("=");
            key = keyValue[0];
            value = StringUtils.isNotBlank(keyValue[1]) ? keyValue[1] : "";
            config.put(key, value);
        }
    }
}

这里的自定义线程你可以去掉,也可以自己定义一个:

@Configuration
public class ThreadConfig {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        return new ThreadPoolExecutor(2,
                4,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }
}

3.自定义一个Config工具类:ZConfigUtil,用来访问配置。

@Component
public class ZConfigUtil {
    @Autowired
    private Map<String, String> zConfig;

    public String getValue(String key) {
        String res = "";
        if (StringUtils.isBlank(key)) {
            return res;
        }
        res = zConfig.get(key);
        return res;
    }
}

二. 测试

Nacos中的配置文件内容:(记得保证你的命名空间、组都和你配置一致)
在这里插入图片描述

我的测试代码:

@GetMapping("/test")
@IgnoreCertification
public CommonReturnType getUser(@RequestParam("key") String key) {
    String value = zConfigUtill.getValue(key);
    return CommonReturnType.creat(value);
}

访问路径:localhost:8003/user/test?key=test ,如图:
在这里插入图片描述

如果我们在Nacos上添加一条配置然后保存:
在这里插入图片描述

可以看到监听器监听到了对应的变更事件:
在这里插入图片描述
所以我代码里面会对\n进行分割:
在这里插入图片描述

三. 展望

其实这个功能,Nacos本身已经支持了,或许还有别的方式可以直接获取相关的配置。只不过我这里自己又写了一个。核心的代码无非就是这段:

Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
ConfigService configService;
try {
    configService = NacosFactory.createConfigService(properties);
    addListener(configService, config);
    String content = configService.getConfig(zkNacosProperties.getFileName(), group, zkNacosProperties.getTimeout());
    updateCache(content, config);
} catch (Exception e) {
    e.printStackTrace();
}

一般项目启动之后,Nacos的配置地址、相关的命名空间都是固定好的。实际开发过程中,文件名称、Key的值往往是可以改变的。无非就是将上面的代码改造一下而已。

剩余的就是看对NacosConfig上的内容如何做处理了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38221.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

博客项目(前台功能实现)

博客项目(前台接口实现) 文章目录博客项目(前台接口实现)1.前置知识1.1Controller1.1.1ResponseResult类1.1.2该类的方法1.2Service1.3ServiceImpl1.4Mapper1.5Vo的理解1.6可能会用到的相关插件1.7设置字面量1.8后端接口测试工具2.热门文章接口分析2.1热门文章接口位置2.2接口的…

Internet Download Manager2023最新版下载器功能介绍

说到下载器在国内就不得不提迅雷&#xff0c;迅雷真是伟大&#xff0c;几乎垄断了国内的下载市场&#xff0c;的确&#xff0c;有的时候用迅雷可以下载到很不错的资源&#xff0c;但在没有VIP的情况下&#xff0c;迅雷是不友好的&#xff0c;相信使用迅雷的各位都有被限速过的经…

三、Eureka

文章目录一、认识服务提供者和服务调用者二、Eureka 的工作流程三、服务调用出现的问题及解决方法四、搭建 eureka-server五、注册 user-service、order-service六、在 order-service 完成服务拉取&#xff08;order 模块能访问 user 模块&#xff09;七、配置远程服务调用八、…

分布式锁:不同实现方式实践测评

Hello读者朋友们&#xff0c;今天打算分享一篇测评实践类的文章&#xff0c;用优雅的代码与真实的数据来讲述在分布式场景下&#xff0c;不同方式实现的分布式锁&#xff0c;分别探究每一种方式的性能情况与最终的优劣分析。 开门见山&#xff0c;我们先看一张表格&#xff0c…

fiddler安卓模拟器与ios手机抓包

一.安卓模拟器(雷电模拟器)抓包 1.1fiddler基本配置 1.2导出Fiddler证书 Tools -> Options -> HTTPS -> Actions -> Export Root Certificate to Desktop 在桌面上看到导出的FiddlerRoot.cer证书文件 1.3下载和安装openssl openssl下载地址 git终端输入 open…

蜂鸟E203学习(一)--RISC的前世今生

第一章 CPU之前世今生 1.1、CPU众生相 1.1.1 处理器&#xff08;cpu&#xff09;和处理器内核&#xff08;core&#xff09;的区分 处理器严格意义上是soc&#xff0c;包含了内核和其他设备或者存储器. 1.1.2 不同CPU架构的诞生时间 CPU架构诞生时间Intel 80861978年ARM19…

Opencv之Mat常用类成员(一篇就够了)

1. 重要类成员 data&#xff1a;数据存储的起始地址 (uchar*类型)&#xff1b;dims&#xff1a;矩阵维度。如 3 * 4 的矩阵为 2 维&#xff0c; 3 * 4 * 5 的为3维&#xff1b;channels()&#xff1a;通道数量&#xff0c;矩阵中表示一个元素所需要的值的个数。例&#xff1a;…

Docker-系统环境

Docker1.Docker与虚拟机的区别2.Docker主要解决的问题3.镜像和容器4.Docker的安装9.查找镜像10.常用命令11.安装数据库12.安装tomcat13.容器使用注意事项1.Docker与虚拟机的区别 Docker是开发运行和部署应用程序的开发管理平台&#xff0c;它类似于虚拟机&#xff0c;可以独立…

七、Feign

文章目录一、Feign实现远程调用1.替换RestTemplate发起远程调用&#xff0c;RestTemplate存在的问题&#xff1a;2.实现Feign远程调用&#xff1a;二、Feign的自定义日志1.Feign可修改的配置如下2.方式一&#xff1a;配置文件方式3.方式二&#xff1a;Java代码方式一、Feign实现…

Qt:信号与槽机制

说实话&#xff0c;Qt给我的感觉像一种魔改版c&#xff0c;不纯粹&#xff0c;看不到内部的源代码&#xff0c;也不知道一些宏是怎么实现的... 信号与槽内部机制 回归正题&#xff0c;其实学过设计模式的应该都能看出来&#xff0c;qt的这个机制是一个观察者模式&#xff1b; …

又解锁了一种OpenFeign的使用方式!

引言 Hello 大家好&#xff0c;这里是Anyin。 在关于OpenFeign那点事儿 - 使用篇 中和大家分享了关于OpenFeign在某些场景下的一些处理和使用方法&#xff0c;而今天Anyin再次解锁了OpenFeign的又一个使用场景&#xff0c;只能说真香。 在我们日常开发中&#xff0c;相信大家…

SSM框架-MyBatis基础

1. MyBatis简介 1.1 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis&#xff0c;2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff0c;iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github。 iBa…

Pipelines in Shell

本篇文章内容需要读者知道 shell 的一些语法和作用&#xff0c;知道 shell 的用途&#xff0c;和一些基本的用法。 这里可以查看原文&#xff1a;Pipelines in Shell 学习 shell 脚本必须要理解 pipeline 的概念&#xff0c;知道 command 的输入&#xff08;input&#xff09;和…

编译概念总结

一个很笨很笨的人的编译自救笔记。 1 程序设计语言 程序设计语言用于书写计算机程序的语言。语言的基础是一组记号和一组规则。根据规则由记号构成的记号串的总体就是语言。在程序设计语言中&#xff0c;这些记号串就是程序。 程序设计语言由三个方面的因素&#xff0c;语法…

[附源码]SSM计算机毕业设计商场日常维修管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

深度学习(19):nerf论文公式理解

注&#xff1a;有问题欢迎评论留言&#xff0c;但尽量不要喷呀。 1. nerf论文第四章翻译如下&#xff1a; 我们的5D神经辐射场将场景表示为空间任意点的体积密度和定向发射辐射&#xff08;directional emitted radiance&#xff09;。我们使用经典体积渲染&#xff08;class…

嗯哦哎辟 2022 游寄

虽然上次不是假的&#xff0c;但这次是真的寄了。 Day 0 虽然是南京本地人&#xff0c;但因疫情原因&#xff0c;晚上决定去住了酒店。 看了一眼考场&#xff0c;感觉位置小得离谱。不愧是 NOI 2022 团体总分第十的“强省”江苏。 刚开始去了 409&#xff0c;发现房间里一股…

C++ 基础入门

1、变量 作用&#xff1a;给一段指定的内存空间起名&#xff0c;方便操作这段内存。 2、常量 作用&#xff1a;用于记录程序中不可更改的数据 C中定义常量的两种方式&#xff1a; #define 宏常量&#xff1a; #define 常量名 常量值const修饰的变量&#xff1a;const数据类型 …

26k Star, 理解Git太轻松了。。。

程序员宝藏库&#xff1a;gitee.com/sharetech_lee/CS-Books-Store Git是目前使用比较广泛一款版本控制工具&#xff0c;从事开发工作&#xff0c;很难绕开Git。 因此&#xff0c;关于如何快速学习Git使用一直都是一个经久不衰的话题。 前不久我在另外一篇文章中曾提到Git对初…

【药材识别】基于色差色温特征结合SVM实现药材炮制程度判断系统附GUI界面

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …