nacos配置动态刷新及监听到变化触发一些方法

news2024/11/26 21:39:09

介绍

在使用spring 时,动态更新配置是常见的,属性值更新,但是需要开启支持刷新功能,一个是spring.cloud.nacos.config.isRefreshEnabled=true; 这个值一般是默认的,可以在nacosConfigProperties这个类中看到。还要在扩展配置中开启refresh = true

spring
    cloud:
      nacos:
        config:
          server-addr: ${nacos-ip}
          extension-configs[0]:
            data-id: ${spring.application.name}.yml
            group: base
        # 这个地方必须开启,否则不会自动刷新
            refresh: true

2 使用

2.1 新建配置类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "apply.demo")
public class DemoConfig {

    /**
     * 配置信息
     */
    private String config;
}

2.2 新建测试访问类


import com.purgeteam.dynamic.config.starter.event.ActionConfigEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@Slf4j
@RequestMapping("/api/test2")
public class Test2Controller {//

    @Autowired
    private DemoConfig demoConfig;



    @GetMapping(value = "dd")
    public String test4(String params){

        log.info("dsds" + params);

        System.out.println(demoConfig.getConfig());
        System.out.println(SpringUtil.getApplicationContext().getBean("testController"));
        // 保存数据
        return demoConfig.getConfig();
    }

}

2.3 yml配置

apply:
  demo:
    config: 2225dssww

测试结果: 配置中心值改变,对应的属性值也改变

------这里好像没用加@RefreshScope注解

3. 监听到变化触发方法

在监听到配置值变化后,需要触发一些方法,需要实现ApplicationListener<T> 接口,重写onApplicationEvent方法

3.1 触发代码


import com.purgeteam.dynamic.config.starter.event.ActionConfigEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@Slf4j
@RequestMapping("/api/test2")
public class Test2Controller implements ApplicationListener<ActionConfigEvent> {//

    @Autowired
    private DemoConfig demoConfig;



    @GetMapping(value = "dd")
    public String test4(String params){

        log.info("dsds" + params);

        System.out.println(demoConfig.getConfig());
        System.out.println(SpringUtil.getApplicationContext().getBean("testController"));
        // 保存数据
        return demoConfig.getConfig();
    }

// 这个方法会在属性变化后调用,这里可以根据某个值变化去处理其他逻辑
    @Override
    public void onApplicationEvent(ActionConfigEvent actionConfigEvent) {
// 获取变化的key
        Map<String, HashMap> propertyMap = actionConfigEvent.getPropertyMap();
// 取出变化的key的map
        HashMap hashMap = propertyMap.get("spring.profiles1.active1");
// 变化后的值
        Object after = hashMap.get("after");
// 变化前的值
        Object after = hashMap.get("before");
// 打印属性值
        log.info("====env========={}",this.demoConfig.getConfig());
    }
}

4. 执行流程分析

处理属性变化绑定值类org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#onApplicationEvent

自己可以打断点,看方法走向。

获取服务端配置最后是一个string,在com.alibaba.nacos.client.config.impl.ClientWorker.LongPollingRunnable#run这个方法中

String[] ct = ClientWorker.this.getServerConfig(dataId, group, tenant, 3000L);

4.1 服务启动注册配置监听

com.alibaba.cloud.nacos.refresh.NacosContextRefresher#onApplicationEvent这里会调用注册方法com.alibaba.cloud.nacos.refresh.NacosContextRefresher#registerNacosListenersForApplications

// 注册监听方法
private void registerNacosListenersForApplications() {
// 全局开启刷新,默认是true
        if (isRefreshEnabled()) {
            for (NacosPropertySource propertySource : NacosPropertySourceRepository
                    .getAll()) {
            // 判断单个配置文件是否支持刷新,就是refresh = true,开启了就会注册监听,有变化就会及时通知
                if (!propertySource.isRefreshable()) {
                    continue;
                }
                String dataId = propertySource.getDataId();
                // 调用注册方法
                registerNacosListener(propertySource.getGroup(), dataId);
            }
        }
    }
private void registerNacosListener(final String groupKey, final String dataKey) {
        String key = NacosPropertySourceRepository.getMapKey(dataKey, groupKey);
        // 创建监听
        Listener listener = listenerMap.computeIfAbsent(key,
                lst -> new AbstractSharedListener() {
                    @Override
                    public void innerReceive(String dataId, String group,
                            String configInfo) {
                        refreshCountIncrement();
                        nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo);
                        // todo feature: support single refresh for listening
                        applicationContext.publishEvent(
                                new RefreshEvent(this, null, "Refresh Nacos config"));
                        if (log.isDebugEnabled()) {
                            log.debug(String.format(
                                    "Refresh Nacos config group=%s,dataId=%s,configInfo=%s",
                                    group, dataId, configInfo));
                        }
                    }
                });
        try {

        // 这里是最重要的,将监听添加到,config里,注册上
            configService.addListener(dataKey, groupKey, listener);
        }
        catch (NacosException e) {
            log.warn(String.format(
                    "register fail for nacos listener ,dataId=[%s],group=[%s]", dataKey,
                    groupKey), e);
        }
    }

4.2 配置改变刷新配置属性

调用到org.springframework.cloud.context.refresh.ContextRefresher#refreshEnvironment


// 返回变化的key
public synchronized Set<String> refreshEnvironment() {
// 以前的配置的值
        Map<String, Object> before = this.extract(this.context.getEnvironment().getPropertySources());
        this.addConfigFilesToEnvironment();
// 改变后的key
        Set<String> keys = this.changes(before, this.extract(this.context.getEnvironment().getPropertySources())).keySet();

// 发布环境变化时间,spring内部事件
        this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
// 返回变化的key
        return keys;
    }

求出以前和现在变化的key

private Map<String, Object> changes(Map<String, Object> before, Map<String, Object> after) {
        Map<String, Object> result = new HashMap();
        Iterator var4 = before.keySet().iterator();

        String key;
        while(var4.hasNext()) {
            key = (String)var4.next();
            if (!after.containsKey(key)) {
                result.put(key, (Object)null);
            } else if (!this.equal(before.get(key), after.get(key))) {
                result.put(key, after.get(key));
            }
        }

        var4 = after.keySet().iterator();

        while(var4.hasNext()) {
            key = (String)var4.next();
            if (!before.containsKey(key)) {
                result.put(key, after.get(key));
            }
        }

        return result;
    }

环境变化事件处理

org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#onApplicationEvent

public void onApplicationEvent(EnvironmentChangeEvent event) {
        if (this.applicationContext.equals(event.getSource()) || event.getKeys().equals(event.getSource())) {
// 重新绑定值
            this.rebind();
        }

    }

这里会看到需要绑定的配置类


开始绑定

这里绑定值后,虽然经过了销毁和初始化,发现,地址没有变,里面的值变了

刷新后还会调用这个方法org.springframework.cloud.context.refresh.ContextRefresher#refresh

发布一个RefreshScopeRefreshedEvent事件

com.purgeteam.dynamic.config.starter.event.DynamicConfigApplicationListener#onApplicationEvent

public void onApplicationEvent(RefreshEvent event) {
        ConfigurableEnvironment beforeEnv = (ConfigurableEnvironment)this.context.getEnvironment();
        MutablePropertySources propertySources = beforeEnv.getPropertySources();
        MutablePropertySources beforeSources = new MutablePropertySources(propertySources);
        Set<String> refresh = this.refresh.refresh();
        Map<String, HashMap> contrast = this.propertyUtil.contrast(beforeSources, propertySources);

// 发布一个配置变化事件
        this.context.publishEvent(new ActionConfigEvent(this, "Refresh config", contrast));
        log.info("[ActionApplicationListener] The update is successful {}", refresh);
    }

调用到自己的方法

public void onApplicationEvent(ActionConfigEvent actionConfigEvent) {
        Map<String, HashMap> propertyMap = actionConfigEvent.getPropertyMap();
        HashMap hashMap = propertyMap.get("spring.profiles1.active1");
        Object after = hashMap.get("after");
// 触发其他逻辑
        log.info("====env========={}",this.demoConfig.getConfig());
    }

5. 总结

这里主要介绍了使用。

如果属性刷新需要处理逻辑,就需要实现ApplicationListener接口

需要注意配置是怎么注册监听的。

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

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

相关文章

【C++】list介绍及使用模拟实现对比vector

文章目录1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator以及insert和erase的使用1.2.3 list的迭代器失效2. list的模拟实现2.1 模拟实现list3.&#xff08;本文精华&#xff09;list与vector的对比1. list的介绍及使用 1.1 list的介绍 …

图像识别AI程序(数据集管理/训练/预测)

出于对Python中AI智能识别程序的兴趣&#xff0c;对照AI智能识别程序应该具有的主要功能&#xff1a;数据集管理&#xff08;加载/移除/重命名&#xff09;、模型训练&#xff08;可实时监测训练进度、最终训练参数输出&#xff09;、模型预测&#xff0c;使用Python/Keras编制…

open-local本地存储使用

Open-local使用指南架构组成1. scheduler-extender&#xff1a; 作为 kube-scheduler 的扩展组件&#xff0c;通过 Extender 方式实现&#xff0c;扩展了原生调度器对本地存储资源的感知&#xff0c;以实现对包括磁盘容量、多盘感知、磁盘介质&#xff08;ssd or hdd&#xff0…

数据分析-深度学习Day5

Backpropagation反向传播我们上节课学习了深度学习&#xff0c;也知道采用梯度下降优化我们的各神经元参数&#xff0c;以语音识别为例&#xff0c;一个输入特征量1000多项&#xff0c;8层隐层&#xff0c;大致需要的w,b参数有数百万项&#xff0c;这样我们梯度下降的计算量是非…

记一次部署在docker环境项目发送邮件出现No appropriate protocol

前言 部门有个项目涉及到邮件发送&#xff0c;发送功能在本地测试可以成功发送&#xff0c;但是打包部署到docker环境中&#xff0c;却出现 No appropriate protocol (protocol is disabled or cipher suites are inappropriate)后面在网上搜索了一下&#xff0c;查到了这篇文…

技术分享 | 测试平台开发-前端开发之Vue.js 框架的使用

首先将 Vue.js 下载到本地&#xff0c;本章就以本地的 Vue.js 为例。在本地创建一个工作区即创建一个文件夹&#xff0c;使用 vscode 打开&#xff0c;将 Vue.js 放到工作区目录下。 创建挂载元素 首先创建一个 index.html 的文件&#xff0c;使用 加载 vue.js&#xff0c;这…

NAT模式虚拟机能ping通宿主机但是telnet不通 教你如何设置网关走出误区

今天跟大家聊聊如何正确配置NAT模式下虚拟机的网关。 如标题所言&#xff0c;我一开始在设置网关的时候一直存在着误区&#xff0c;而这个误区也导致标题中的问题&#xff1a;虚拟机能ping通宿主机&#xff0c;但是telnet不通&#xff0c;这就很奇葩了。 如下网络拓扑图。 虚…

Linux ALSA 之五:ALSA Proc Info

ALSA Proc Info一、概述二、Proc Files of Alsa Driver1、/proc/asound/xxx 简述2、创建 /proc/asound 目录树2.1 /proc/asound/version 文件2.2 /proc/asound/devices 文件2.3 /proc/asound/cards 文件2.4 /proc/asound/cardx 目录2.5 /proc/asound/pcm 文件一、概述 Linux系…

企业不可忽视的舆情监测管理办法,TOOM舆情监控工作总结?

企业做好舆情监控以及舆情管理是对企业负责&#xff0c;在企业发展过程中不可能是一帆风顺的&#xff0c;少不了各种各样的流言蜚语&#xff0c;像舆情监控管理监测早知早解决。接下来我们简单了解企业不可忽视的舆情监测管理办法&#xff0c;TOOM舆情监控工作总结? 一、企业…

【NI Multisim 14.0原理图设计基础——调整元器件位置】

目录 序言 一、调整元器件位置 &#x1f34a;1.元器件的移动 &#x1f34a;2.元器件的旋转 &#x1f34a;3.元器件的对齐 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI…

【自学Python】Python print()函数

Python print()函数 Python print()函数教程 在 Python 中&#xff0c;print() 函数用于打印相应的信息到终端控制台&#xff0c;同时 print() 函数可以支持同时输出一个或多个 变量。 Python print()函数详解 语法 print(*objects, sep , end\n, filesys.stdout, flushFa…

线性代数 --- 投影Projection 六(向量在子空间上的投影)

向量b在多维子空间上的投影回顾&#xff1a;向量在向量上&#xff08;直线上&#xff09;的投影在研究向量在子空间上的投影前&#xff0c;先回顾一下前面学习的一个任意向量b在另一个向量a上的投影&#xff0c;共三个部分。1&#xff0c;求权重系数&#xff08;A constant&…

2022 general purpose in-context learning by meta-learning transformers

wps: option left 回到上一个视图 Kirsch L, Harrison J, Sohl-Dickstein J, et al. General-purpose in-context learning by meta-learning transformers[J]. arXiv preprint arXiv:2212.04458, 2022. 目录Kirsch L, Harrison J, Sohl-Dickstein J, et al. General-purpose…

【高校节能】高校电力能源智能管理系统设计目标与原则

摘 要&#xff1a;高校构建电力能源智能管理系统&#xff0c;可以实现对高校电力能源消耗的实时监测、分析预警和辅助决策。系统通过能效管理技术监测各个设备的用电情况&#xff0c;并通过数据的取得、整合、汇总来实现能源的绩效管理。系统从全局出发&#xff0c;整体调控电…

CCF BDCI | 算能赛题决赛选手说明论文-03

基于TPU平台实现人群密度估计∗ ChaMd5-AI 唐晶机械工程&博士二年级 华中科技大学 中国-武汉 j_tanghust.edu.cn 团队简介 唐晶&#xff0c;2001年生&#xff0c;本科毕业于华中科技大学机械卓越工程师班&#xff0c;现为华中科技大学机械科学与工程学院陶波教授课题组博…

视频实时自然美颜, 无惧素颜上镜

华为HMS Core 视频编辑服务依托自身AI技术的核心优势&#xff0c;在最新版本HMS Core 6.8.0中上线了全新的视频美颜功能&#xff0c;能对指定图片或视频中的人脸实现磨皮、美白、大眼、瘦脸的美颜效果&#xff0c;适用于直播、相机、视频剪辑、图片处理等场景中&#xff0c;打造…

cubeIDE开发, stm32的GPIO原理、cubeMX配置及底层源码实现分析

一、GPIO介绍 1.1 GPIO 简述 GPIO(General purpose input/output&#xff0c;通用型输入输出)&#xff0c;一个引脚可以用于输入、输出或其他特殊功能&#xff0c;PIN脚依现实需要可作为通用输入&#xff08;GPI&#xff09;或通用输出&#xff08;GPO&#xff09;或通用输入与…

鑫磊股份开启申购:资产负债率较高,实控人控制企业借款高企

1月10日&#xff0c;鑫磊压缩机股份有限公司&#xff08;下称“鑫磊股份”&#xff0c;SZ:301317&#xff09;开启申购&#xff0c;发行价格20.67元/股&#xff0c;市盈率58.65倍。据贝多财经了解&#xff0c;鑫磊股份将在深圳证券交易所创业板上市。 本次上市&#xff0c;鑫磊…

LinuxC—进程

进程 1 进程标识符pid 基本概念 类型pid_t&#xff0c;是一个有符号16位整数&#xff0c;进程号是顺次向下使用(fd是优先使用当前可用最小的) shell中的ps命令能够查看当前系统的进程信息快照 相关函数 getpid(2)获取当前进程的进程号 /* Get the process ID of the calling…

中断处理程序

文章目录前言前置知识中断概念中断分类实验操作实验一实验二实验三前言 博客记录《操作系统真象还原》第七章实验的操作~ 实验环境&#xff1a;ubuntu18.04VMware &#xff0c; Bochs下载安装 实验内容&#xff1a; 编写中断处理程序&#xff08; 操作 8259A 打开中断&…