Nacos 中配置 Map 类型,不香
最近在使用 Nacos 过程中遇到一个场景,配置的字符串可以解析成 Map 类型使用,有一个配置如下:
map:test: key1:value1,key2:value2,key3:value3
后来有同事建议 Nacos 可以直接配置成 Map 类型,后台使用 Java Map 类型获取就可以。配置如下:
map:test:key1: value1key2: value2key3: value3
下面就来分享一下配置 Map 类型的过程中遇到的问题。
1 使用 Bean 方式获取配置
1.1 使用方式
参考网上的一些案例,第一个方式是把读取到的 Map 作为一个 Spring 的 Bean,一看代码就明白了。
@Bean @ConfigurationProperties(prefix = "map.test") public Map<String, String> mapping() {return new HashMap<>(); }
1.2 槽点
这样确实可以把 Nacos 中读取到的配置转换成 Map 类型,但一个致命的槽点就是 mapping 这个 bean 不能自动刷新。这样如果修改了 Nacos 中配置,要想让配置生效,就必须重启应用服务,这怎么能接受呢?
2 ConfigurationProperties2.1 使用方式
直接使用 @Value 和 @NacosValue 是获取不到值的。下面的这种方式,类的定义上加注解 @ConfigurationProperties,再定义一个变量,名称跟 Nacos 中配置的后缀一样,这样是可以获取到 Map 类型的配置的。
@Component @RefreshScope @ConfigurationProperties(prefix = "map") public class NacosRefresh {private Logger logger = LoggerFactory.getLogger(getClass());public void setTest(Map<String, String> test) {this.test = test;}private Map<String, String> test; }
注意:上面的 setTest 方法是必须要的,不然 test 变量取不到值。
2.2 槽点
这样确实可以把 Nacos 中读取到的配置转换成 Map 类型,但是跟第一种方式一样,定义的 Map 类型变量不能自动刷新。
3.使用监听
Nacos API 提供了监听功能,可以监听配置的变化,对变化进行处理,只要在监听方法上增加 @NacosConfigListener 这个注解就可以生效。见下面代码:
@Service public class NacosListener {private Logger logger = LoggerFactory.getLogger(getClass());private Map<String, String> map = new HashMap<>();@NacosConfigListener(dataId = "maptest.yaml",groupId = "DEFAULT_GROUP")public void listener(String context){logger.info("================listener context:{}", context);if (StringUtils.isBlank(context)){return;}Yaml yaml = new Yaml();Map<String, Object> contextMap = yaml.load(context);Map<String, Object> map = (Map<String, Object>)contextMap.get("map");if (CollectionUtils.isEmpty(map)){return;}Map<String, String> test = (Map<String, String>) map.get("test");if (CollectionUtils.isEmpty(test)){return;}map.clear();map.putAll(test);map.forEach((k,v) -> logger.info("Entry in map, key:{},value:{}", k, v));} }
这段代码是从 Nacos 配置中解析出 Map 类型的配置,然后把配置 put 到本地变量 map。这个也可以完成我们的需求,但是有几点需要注意。
3.1 服务重启
如果服务重启了,本地变量 map 拉不到值。因为上面监听的逻辑并没有走,即使在 Nacos 上重新发布一下,也不行。
上面的监听方法,只有在 Nacos 配置发生变化并且发布后才会触发,比如 map.test 配置改变如下:
map:test:key1: value1key2: value2key3: value3key4: value4
3.2 并发问题
上面监听的代码里面,需要把本地变量 map 先 clear 然后再 putAll,如果这两个方法调用中间发生了线程上下文切换,读取线程可能会因为从 map 中取不到值而发生异常。
4.改进
上面讲解了使用 Nacos 配置 Map 类型的坑,不过使用 Nacos 配置 Map 类型也有个好处,不用解析字符串,直接可以转成 Map 类型。
4.1 使用字符串
完全不使用 Map 类型了,改成配置字符串,配置如下:
map:test: key1:value1,key2:value2,key3:value3
解析代码如下:
@NacosValue(value = "${map.test}", autoRefreshed = true) private String mapTest;public String get(String key){String[] keys = mapTest.split(",");for (String item : keys){if (!item.contains(key)){continue;}return item.split(":")[1];}return null; }
这种写法的好处是不用监听 Nacos,配置改变后 mapTest 变量自动刷新,缺点是每次调用 get 方法都需要解析 mapTest 这个字符串。
4.2 刷新本地 Map
把解析字符串的结果放到本地变量 map 上,考虑到 Nacos 中配置可能会发生变化,用定时线程池每 1 秒刷新一次,代码如下:
private Map<String, String> map = new HashMap<>();@NacosValue(value = "${map.test}", autoRefreshed = true) private String mapTest;@PostConstruct public void refreshLocalMap(){ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);scheduled.scheduleAtFixedRate(() -> refresh(), 0, 1000, TimeUnit.MILLISECONDS); }public void refresh(){String[] keys = mapTest.split(",");for (String item : keys){String[] kv = item.split(":");map.put(kv[0], kv[1]);} }
这个写法的好处是不用每次调用都解析字符串,而是由异步线程每秒钟刷新。但是也有两个问题:
- 需要一个定时线程池,会消耗 CPU 资源。
- refresh 方法是每秒执行一次,会有短暂的本地变量和 Nacos 配置不一致的问题。
5.总结
Nacos 中配置 Map 类型确实不香,主要原因是刷新不方便。但是对于配置不需要刷新的场景,还是很有好处的,尤其是 key 比较多的时候,比解析字符串方便很多,而且 Hash 的时间复杂度是 o(1) ,在数据结构中是最优秀的。
对于需要刷新的场景,无论使用哪种方案,都有优缺点,没有最好的,只有最适合的,要根据系统的业务场景来做选择。
Nacos 中配置 Map 类型,不香相关推荐
- 在IIS中配置MIME类型组建Wap网站
1.创建站点文件夹 首先你要在IIS上创建一个新的站点. 2.创建新的MIME类型 首先选择"WAP"站点的"属性",然后选择"HTTP 头" ...
- Spring Cloud Alibba教程:如何使用Nacos作为配置中心
点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 在上一篇文章中讲解了如何使用Nacos作为服务注册中心注册.Nacos除了可以作为服务注册中心, ...
- Linux启动nacos成功日志_Spring Cloud Alibaba基础教程:使用Nacos作为配置中心
通过本教程的前两篇: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方 ...
- Spring Cloud Alibaba基础教程:使用Nacos作为配置中心
通过本教程的前两篇: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方 ...
- Nacos分布式配置实践
本文来说下Nacos分布式配置如何来实践 文章目录 概述 创建服务 Nacos中新建配置 服务整合Nacos配置 动态刷新 本文小结 概述 本文目的是使用 Nacos 管理服务的配置. 步骤: (1) ...
- eBPF: 深入探究 Map 类型
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可. 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权. 内核版本为5.4.119 文章目录 ...
- SpringCloud读取Nacos中的配置文件
目录 一.配置nacos命名空间 1.通过安装路径启动nocas 2.通过localhost:8848进入nacos的页面,账号密码都为nacos 3.添加命名空间 ?3.1添加三个命名空间分别为:d ...
- java怎么设置不同事件_activiti 全局流程监听ActivitiEventListener,实现监听不同类型事件,不需要在acitivit中配置任务监听,非常方便...
如果我们像给任务配置监听,按照常规的做法是这样的 一个个配置,比较麻烦. 现在利用ActivitiEventListener,监听全局事件,并且可以判断不同的事件类型,进而执行不同的业务逻辑. 1.定 ...
- SpringCloud(若依微服务版)读取Nacos中的配置以及多个服务共享Nacos配置的使用
场景 若依微服务版手把手教你本地搭建环境并运行前后端项目: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/109363303 在上 ...
- java中map转为json数据_Java技术-将java中Map类型数据转化为json数据并以Ajax形式返回...
Java技术-将java中Map类型数据转化为json数据并以Ajax形式返回html 1.自定义工具类(简单易用)-下面是我写的一个简单的工具类前端 package com.test.util; i ...
最新文章
- Spring Boot + Vue + Shiro 实现前后端分离、权限控制
- 2017年第十一届中国电子产业品牌盛会盛大开启
- Gradient Boost 算法流程分析
- 中 找多个平面_数学一轮复习30,平面向量的概念及线性运算,三个常用结论
- WebRTC 系列之音频会话管理
- VirtualBox安装linux mint教程
- 第三次学JAVA再学不好就吃翔(part36)--抽象类
- 一号团队-团队任务3:每日立会(2018-12-01)
- 【Spring AOP】AOP 底层实现原理 —— 动态代理类的创建(JDK、CGlib)、工厂如何加工原始对象
- java 链表算法_数据结构算法Java版(一) 链表
- 微机接口技术实用教程(第2版)-任向民,王克朝,宗明魁-课后答案
- day7--pandas
- 如何在PHP中获得有用的错误消息?
- 小米9008授权账号_小米AI音箱APP的秘密
- word如何批量免费转PDF
- 使用 Tampermonkey 编写高级跨网站自动化任务脚本
- 示例填充图片_用示例解释洪水填充算法
- 安卓视频播放器(TV)
- 【C++探索之旅】第一部分第八课:传值引用,文件源头
- 做Android开发 需要掌握哪些知识
热门文章
- 以太网卡支持的工作模式
- SSM | Spring
- 深度:融360还是一家有价值的公司吗?
- linux和windows文件加密,在Linux和 Windows 上使用 EncFS,如何加密雲存儲
- 自定义UISearchBar 适配IOS6和IOS7 修改放大镜图标 修改光标颜色 修改边框颜色 placeholder颜色 设置文本框背景
- K-periodic Garland
- Java使用微软Exchange邮箱发送与接收邮件
- 充分利用微博加快社区发展
- 卸载360企业版密码
- From Intrusion Detection to Attacker Attribution: A Comprehensive Survey of Unsupervised Methods翻译