您现在的位置是:亿华云 > 应用开发
Nacos 中配置 Map 类型,不香!
亿华云2025-10-04 03:43:06【应用开发】6人已围观
简介大家好,我是君哥。最近在使用 Nacos 过程中遇到一个场景,配置的字符串可以解析成 Map 类型使用,有一个配置如下:map:test: key1:value1,key2:value2,key3:v
大家好,不香我是配置君哥。
最近在使用 Nacos 过程中遇到一个场景,不香配置的配置字符串可以解析成 Map 类型使用,有一个配置如下:
map:
test: key1:value1,不香key2:value2,key3:value3
后来有同事建议 Nacos 可以直接配置成 Map 类型,后台使用 Java Map 类型获取就可以。配置配置如下:
map:
test:
key1: value1
key2: value2
key3: value3
下面就来分享一下配置 Map 类型的不香过程中遇到的问题。
1.使用 Bean 方式获取配置
1.1 使用方式参考网上的配置一些案例,第一个方式是不香把读取到的 Map 作为一个 Spring 的 Bean,一看代码就明白了。配置
@Bean
@ConfigurationProperties(prefix = "map.test")
public Map
return new HashMap<>();
}1.2 槽点这样确实可以把 Nacos 中读取到的配置转换成 Map 类型,但一个致命的配置槽点就是 mapping 这个 bean 不能自动刷新。这样如果修改了 Nacos 中配置,不香要想让配置生效,配置就必须重启应用服务,不香这怎么能接受呢?
2.ConfigurationProperties
2.1 使用方式直接使用 @Value 和 @NacosValue 是获取不到值的。下面的这种方式,类的定义上加注解 @ConfigurationProperties,再定义一个变量,云服务器提供商名称跟 Nacos 中配置的后缀一样,这样是可以获取到 Map 类型的配置的。
@Component
@RefreshScope
@ConfigurationProperties(prefix = "map")
public class NacosRefresh {
private Logger logger = LoggerFactory.getLogger(getClass());
public void setTest(Map
this.test = test;
}
private Map
注意:上面的 setTest 方法是必须要的,不然 test 变量取不到值。
2.2 槽点这样确实可以把 Nacos 中读取到的配置转换成 Map 类型,但是跟第一种方式一样,定义的 Map 类型变量不能自动刷新。
3.使用监听
Nacos API 提供了监听功能,可以监听配置的变化,对变化进行处理,只要在监听方法上增加 @NacosConfigListener 这个注解就可以生效。见下面代码:
@Service
public class NacosListener {
private Logger logger = LoggerFactory.getLogger(getClass());
private Map
@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
Map
if (CollectionUtils.isEmpty(map)){
return;
}
Map
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: value1
key2: value2
key3: value3
key4: value43.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
@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) ,在数据结构中是最优秀的。
对于需要刷新的场景,无论使用哪种方案,都有优缺点,没有最好的,只有最适合的,要根据系统的业务场景来做选择。
很赞哦!(14)
相关文章
- 3、不明先知,根据相关征兆预测可能发生的事件,以便提前做好准备,赶紧注册相关域名。;不差钱域名;buchaqian抢先注册,就是这种敏感类型。预言是最敏感的状态。其次,你应该有眼力。所谓眼力,就是善于从社会上时不时出现的各种热点事件中获取与事件相关的域名资源。眼力的前提是对域名领域的熟悉和丰富的知识。
- 系统管理员宝典:2019年7种实用的编程语言
- 互联网巨头都在研究的无服务器架构,看完收获满满
- 浅谈正则表达式原理
- 一下域名,看有没有显示出你所解析的IP,如果有,就说明解析是生效的;如果没有,就说明解析是不生效的。
- 盘点:2019年前端技术趋势
- 图解九大编程语言之争,到底谁才是Number 1 ?
- HTML5开发者:10个开发便利快捷的小工具
- 3、考虑出售域名
- GitHub的十大JavaScript项目