当前位置: 代码网 > it编程>编程语言>Java > Spring动态监听Nacos配置中心key值变更的实现方法

Spring动态监听Nacos配置中心key值变更的实现方法

2024年08月15日 Java 我要评论
背景:nacos本身提供支持监听配置变更的操作,但在使用起来,个人感觉不是很友好,无法精确到某个key的变更监听实现方法:1. 自定义一个只能用在方法上的注解(当然你也可以自定义不仅仅用在方法上)@t

背景:

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值变更内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com