背景:
nacos本身提供支持监听配置变更的操作,但在使用起来,个人感觉不是很友好,无法精确到某个key的变更监听
实现方法:
1. 自定义一个只能用在方法上的注解(当然你也可以自定义不仅仅用在方法上)
@target({elementtype.type, elementtype.method}) @retention(retentionpolicy.runtime) public @interface configlistener { /** * 待监听的key或key前缀 */ string key(); }
2. 添加具体实现
@slf4j @configuration public class refreshenvironmentconfig implements applicationlistener<environmentchangeevent>, environmentaware, beanpostprocessor { private environment environment; private final map<string, map<method, object>> listeners = new concurrenthashmap<>(64); private final set<class<?>> nonannotatedclasses = collections.newsetfrommap(new concurrenthashmap<>(64)); @override public object postprocessafterinitialization(object bean, string beanname) throws beansexception { if (!this.nonannotatedclasses.contains(bean.getclass())) { class<?> targetclass = aoputils.gettargetclass(bean); map<method, configlistener> annotatedmethods = methodintrospector.selectmethods(targetclass, this::findlistenerannotations); if (!annotatedmethods.isempty()) { for (map.entry<method, configlistener> entry : annotatedmethods.entryset()) { listeners.computeifabsent(entry.getvalue().key(), k -> new hashmap<>()).put(entry.getkey(), bean); log.info("register @configlistener methods processed on bean {} listener key {}", beanname, entry.getvalue().key()); } } this.nonannotatedclasses.add(bean.getclass()); } return bean; } @override public void onapplicationevent(environmentchangeevent event) { set<string> keys = event.getkeys(); keys.foreach(key -> { string value = environment.getproperty(key); int index = 0; do { index = key.indexof(".", index + 1); string subkey = index > 0 ? key.substring(0, index) : key; map<method, object> methodmap = listeners.get(subkey); if (methodmap != null) { methodmap.foreach((method, bean) -> { try { method.invoke(bean, key, value); } catch (illegalaccessexception | invocationtargetexception e) { log.error("refresh @configlistener {}, error {}", bean, e.getmessage(), e); } }); } } while (index > 0); }); } @override public void setenvironment(environment environment) { this.environment = environment; } private configlistener findlistenerannotations(method method) { return findlistenerannotationsbyannotatedelement(method); } private configlistener findlistenerannotationsbyannotatedelement(annotatedelement element) { return annotationutils.findannotation(element, configlistener.class); } }
3. demo
@configlistener(key = "test.value") public void listener1(string key, string newvalue) { log.info("listener1 listened {}-->{}", key, newvalue); } @async @configlistener(key = "test") public void listener2(string key, string newvalue) { log.info("listener2 listened {}-->{}", key, newvalue); }
已上实现,不仅仅适用于nacos,理论上也适用于其他配置中心,(个人仅验证过nacos)
拓展:spring监听nacos配置中心文件变化的两种方式
1.前置条件
1.1依赖
<properties> <spring-boot.version>2.4.2</spring-boot.version> <spring-cloud.version>2020.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version> </properties> <dependencies> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-bootstrap</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-webflux</artifactid> </dependency> <dependency> <groupid>com.alibaba.cloud</groupid> <artifactid>spring-cloud-starter-alibaba-nacos-config</artifactid> </dependency> <dependency> <groupid>com.alibaba.cloud</groupid> <artifactid>spring-cloud-starter-alibaba-nacos-discovery</artifactid> </dependency> </dependencies>
spring-cloud-starter-bootstrap需要引入
1.2配置
1.2.1 nocos配置
我们要监听other.yaml文件的other.name|age属性
1.2.2 bootstrap.yml文件内容
server: port: 8080 --- spring: application: #需要指定 name: gateway profiles: active: dev --- spring: cloud: nacos: discovery: #需要配置 server-addr: 192.168.56.150:8848 group: default_group config: #需要配置 server-addr: 192.168.56.150:8848 group: default_group file-extension: yaml extension-configs: - data-id: gateway-routes.yaml group: default_group refresh: true - data-id: other.yaml group: default_group refresh: true
1.3属性文件映射
@refreshscope//bean 在运行时刷新 @configurationproperties(prefix = "other")//要绑定外部属性的前缀 @configuration//设置为bean public class config { //映射other.yaml ->oher.name private string name; //映射other.yaml ->oher.age private string age; //启动后定时打印当前bean中的值,不推荐这种方式,做测试方法 @postconstruct public void testvalueischange() { new thread(() -> { int i = 1; do { config bean = springbeanutil.getbean(config.class); system.out.println("--- >" + i + "-->当前bean值: " + "name:" + bean.getname() + "|age:" + bean.getage()); try { thread.sleep(3000); } catch (interruptedexception e) { throw new runtimeexception(e); } i++; } while (true); }).start(); } //....get/set方法 }
2监听
2.1第一种方式nacos的sdk
@component public class otherlisten { @resource//注入nacosconfigmanager public void nacoslisten(nacosconfigmanager nacosconfigmanager) { //获取配置中心服务 configservice configservice = nacosconfigmanager.getconfigservice(); try { //对配置中心添加监听(配置文件的dataid,group) configservice.addlistener("other.yaml", "default_group", new abstractconfigchangelistener() { //监听后的处理逻辑 @override public void receiveconfigchange(configchangeevent configchangeevent) { for (configchangeitem changeitem : configchangeevent.getchangeitems()) { system.out.println("nacos方式监听" + changeitem.getkey() + "-----" + changeitem.getnewvalue()); } } }); } catch (nacosexception e) { throw new runtimeexception(e); } } //注解监听spring.cloud环境下需要添加额外依赖,可以参考官方文档,这里不做演示 @nacosconfiglistener(dataid = "other.yaml") public void onreceived(string value) { system.out.println("onreceived : " + value); } }
2.2第二种方式监听spring的环境修改
//利用spring事件通知机制
@component public class otherlisten implements applicationlistener<environmentchangeevent> { @resource private configurableenvironment environment; @override public void onapplicationevent(environmentchangeevent event) { for (string key : event.getkeys()) { system.out.println("spring方式监听: key:" + key + "value:" + environment.getproperty(key)); } } }
3.测试
- 启动后,正常读取到nacos other.yaml数据
- 修改nacos other.yaml数据
- 查看监听是否正常
spring监听正常
nacossdk监听正常
到此这篇关于spring动态监听nacos配置中心key值变更的实现方法的文章就介绍到这了,更多相关spring动态监听nacos key值变更内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论