Springboot 接口方式硬通知实现 动态刷新配置值,@ConfigurationProperties 、@Value 都可以

前言


看到这个文章标题,也许有的看官就觉得很多余, 

因为Nacos 可以设置    @NacosValue(value = "${XXX}",autoRefreshed = true) 实现动态刷新;

又因为cloud config的@RefreshScope   实现动态刷新;

还有阿波罗...等

这些玩意的原理其实都很简单,简单说 就是检测到配置文件的修改项后,发布内容变更事件,然后重新刷新绑定值。

那如果我说不准用这些东西呢?

现在就是一个老项目,不给整合这些阿猫阿狗,我想问阁下应该如何应对?

ps: 最近有个朋友在整改旧项目,做了一套小的配置中心系统,在这个配置平台系统上,通过页面能够动态修改刷新配置值。  做完后,这个朋友有些心得,想分享一下。

不多说,开搞。

正文

我们结合示例玩一下。

@Value

@ConfigurationProperties


 

对应代码:
 

@Component
public class YouInfos {
   @Value("${u.infos.name}")
    private String name;
   @Value("${u.infos.age}")
    private Integer age;
    @Autowired
    private Environment env;
    public String getName() {
        return env.getProperty("u.infos.name");
    }
    public Integer getAge() {
        return Integer.valueOf(Objects.requireNonNull(env.getProperty("u.infos.age")));
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "YouInfos{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
@Component
@ConfigurationProperties(prefix = "my.infos")
public class MyInfos {
    private String name;
    private Integer age;
    @Autowired
    private Environment env;

    public String getName() { return env.getProperty("my.infos.name"); }
    public void setName(String name) { this.name = name; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }

    @Override
    public String toString() {
        return "MyInfos{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

对应application.yml的配置(当然也可以是自己额外的配置文件值):

my:
  infos:
    name: JCccc
    age: 18

u:
  infos:
    name: Doli
    age: 25

细心的看官,看到这里,已经发现了一些不同。

是的 我把配置项的属性字段的get方法,魔改了一下,写成了重新在 Environment 再拿一次。

简单来说,我希望哪些字段属性是可以达到获取实时数据的,那我就改掉这个字段属性的get方法,让它从头再来过,去 Environment 再拿一次 自己。

接下来,就是我们怎么去改 Environment 里面的key属性值。

结合源码实操玩一下。

① 把环境配置属性拿出来 

  private static ConfigurableEnvironment environment;

  MutablePropertySources propertySources   = environment.getPropertySources();

可以看到,这8组配置属性里面, 有一组的名字包含了 application.yml 。

点进去看看是什么:

没错,就是我们的yml 的key 以及value 。

看到这, 大家思路已经比较开明了吧, 我们把这个玩意拿出来, 我们改了哪些key就对应改哪些key(当然新增了哪些,也可以对应去搞)。

看一下这个玩意MutablePropertySources  的源码:

好好好,这么玩是吧,又private 又final 。

这样的情况,我们如何应对?

那当然是最简单的暴力破解 ,反射了: 

            Field valueFieldOfPropertySources = MutablePropertySources.class.getDeclaredField("propertySourceList");
            //设置value属性的访问权限为true
            valueFieldOfPropertySources.setAccessible(true);
            //获取对象上的value属性的值
            List<PropertySource<?>> valueList = (List<PropertySource<?>>) valueFieldOfPropertySources.get(propertySources);
 

这样我们就把这八组的值拿出来了, 然后就遍历,然后把这个 OriginTrackedMapPropertySource(yml的配置值) 拿出来,改完值,再丢回去, 完事。

代码:

MyRefreshConfigUtil.java
 

import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author JCccc 2023-08-01
 */

@Component
public class MyRefreshConfigUtil implements EnvironmentAware {

    private static ConfigurableEnvironment environment;

    public static void refreshValue(String key, Object newValue)  {
        try {

            MutablePropertySources propertySources   = environment.getPropertySources();
            Field valueFieldOfPropertySources = MutablePropertySources.class.getDeclaredField("propertySourceList");
            //设置value属性的访问权限为true
            valueFieldOfPropertySources.setAccessible(true);
            //获取对象上的value属性的值
            List<PropertySource<?>> valueList = (List<PropertySource<?>>) valueFieldOfPropertySources.get(propertySources);
            for (PropertySource<?> propertySource :valueList){
                if (propertySource instanceof OriginTrackedMapPropertySource){
                    Map<String, Object> source = (Map<String, Object>) propertySource.getSource();
                    Map<String, Object> map = new HashMap<>(source.size());
                            map.putAll(source);
                            map.put(key, newValue);
                    environment.getPropertySources().replace(propertySource.getName(), new OriginTrackedMapPropertySource(propertySource.getName(), map));
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        MyRefreshConfigUtil.environment = (ConfigurableEnvironment) environment;
    }
}

代码简析 :


那么我们再暴露出一个api 接口 ,满足key 和 value的实时刷新(可以写成批量,这里就简单写个单个key意思下):
 

    @GetMapping("/doRefresh")
    public String doRefresh(@RequestParam String key ,@RequestParam String value) {
        MyRefreshConfigUtil.refreshValue(key, value);
        return  "refresh success";
    }

也写个简单的获取配置值接口,看看整体的效果:
 

    @Autowired
    MyInfos myInfos;
    @Autowired
    YouInfos youInfos;

    @GetMapping("/getInfos")
    public String getInfos() {
        String myName = myInfos.getName();
        String yourName = youInfos.getName();
        return myName+"---"+yourName;
    }

服务跑起来,先看看我们的配置值:

接下来,我们去修改配置项,然后检测到了配置项哪些key做了改动(这些需要配合前端页面系统化去做比较流畅,就像是一些配置中心页面的保存按钮),然后调用我们的key刷新通知接口:

 

再调用看下我们的配置值:

好了,就这样吧。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】VS配置OpenCV/Libtorch环境

前言 本文是视频https://www.bilibili.com/video/BV1dp4y177L4的笔记。 OpenCV和Libtorch安装包&#xff1a;https://pan.baidu.com/s/1i3DqTcHFSC1rRDsIgYGCsQ?pwd8888 VS版本&#xff1a;2019 Opencv版本&#xff1a;3.4.1 Libtorch版本&#xff1a;2.0.1cu117 配置Open…

TCP之三次握手四次挥手

在前面的文章中我们了解到http是基于TCP/IP协议的&#xff0c;这篇文章我们来了解一下TCP/IP。 一、TCP与UDP 1、UDP 基于非连接。类似于写信&#xff0c;不能保证对方能不能接收到&#xff0c;接收到的内容是否完整&#xff0c;顺序是否正确。 优缺点&#xff1a;性能损耗小…

el-select实现懒加载

先看一个线上的演示示例&#xff1a;https://code.juejin.cn/pen/7273352811440504889 背景 我们在实际开发中经常遇到这样的需求&#xff1a; el-select实现懒加载&#xff0c;用通俗的话说&#xff0c;为了增加响应速度&#xff0c;就是初始下拉只展示50条数据&#xff0c…

excel 分组排序

excel中会遇到对不同分组数据进行排序&#xff0c;比如对于不同班级里的学生按照分数高低进行升序排序&#xff0c;可以采用如下公式 SUMPRODUCT((A$2:A$12A2)*(C$2:C$12>C2))1 如果需要 进行降序排序&#xff0c;将公式中的大于号替换为小于号即可

Unity UI与粒子 层级问题Camera depth Sorting Layer Order in Layer RenderQueue

Unity游戏开发中&#xff0c;模型、界面、特效等&#xff0c;需要规划好layer的概念&#xff0c;涉及到摄像机&#xff08;Camera&#xff09;、画布&#xff08;Canvas&#xff09;、Shader等相关内容。 在 Unity 中&#xff0c;渲染顺序是由多个因素共同决定的&#xff0c;大…

【暴力DP】2021 icpc上海 I

Problem - I - Codeforces 题意&#xff1a; 思路&#xff1a; 考虑暴力DP即可 设 dp[i][j][k]表示 前 i 个物品&#xff0c;已经翻倍了 j 次&#xff0c;A点数 - B点数为 k 的最大价值和 然后分为这6种决策分类讨论就好了 注意数组里不能有负数&#xff0c;要加个偏移量 P…

百度文心一率先言向全社会开放 应用商店搜“文心一言”可直接下载

8月31日&#xff0c;文心一言率先向全社会全面开放。广大用户可以在应用商店下载“文心一言APP”或登陆“文心一言官网”&#xff08;https://yiyan.baidu.com&#xff09; 体验。同时&#xff0c;企业用户可以直接登录百度智能云千帆大模型平台官网&#xff0c;调用文心一言能…

Kubernetes技术--k8s核心技术 configMap

1.概述 configMap最主要的作用是存储一些不加密的数据到/etcd,让pod以变量或者数据卷(volume)挂载到容器。 应用场景:配置文件、存储信息等 2.使用 -1.创建配置文件。 这里我们需要先编写一个配置文件。使用redis,如下所示:

k8s使用ECK(2.4)形式部署elasticsearch+kibana-http协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、准备elasticsearch-cluster.yaml二、部署并测试总结 前言 之前写了eck2.4部署eskibana&#xff0c;默认的话是https协议的&#xff0c;这里写一个使用http…

SpringCloud(十)——ElasticSearch简单了解(三)数据聚合和自动补全

文章目录 1. 数据聚合1.1 聚合介绍1.2 Bucket 聚合1.3 Metrics 聚合1.4 使用 RestClient 进行聚合 2. 自动补全2.1 安装补全包2.2 自定义分词器2.3 自动补全查询2.4 拼音自动补全查询2.5 RestClient 实现自动补全2.5.1 建立索引2.5.2 修改数据定义2.5.3 补全查询2.5.4 解析结果…

面试官如何考察与CAP相关的理论?

在互联网技术面试中&#xff0c;考察分布式技术已经是面试的标配了。很多招聘信息中&#xff0c;你能发现&#xff0c;一线互联网公司在对候选人的要求中都有“分布式系统设计”这一关键词。无论你是程序员&#xff0c;还是架构师&#xff0c;都要掌握分布式系统设计。 案例背…

vue使用打印组件print-js

项目场景&#xff1a; 由于甲方要求&#xff0c;项目需要打印二维码标签&#xff0c;故开发此功能 开发流程 安装包&#xff1a;npm install print-js --saveprint-js的使用 <template><div id"print" ref"print" ><p>打印内容<p&…

WebSocket 协议及其使用案例

文章目录 前言一、初识 WebSocket 协议1.1 什么是 WebSocket 协议1.2 WebSocket 与 HTTP 的关系1.3 WebSocket 握手的过程1.4 WebSocket 解决了什么问题 二、WebSocket 数据帧格式2.1 WebSocket 数据帧格式图示2.2 各字段的详细说明 三、SpringBoot 项目中引入 WebSocket3.1 创…

python中的文件操作

我们平常对文件的基本操作&#xff0c;大概可以分为三个步骤&#xff08;简称文件操作三步走&#xff09;&#xff1a; ① 打开文件 ② 读写文件 ③ 关闭文件 【注意事项】 注意&#xff1a;可以只打开和关闭文件&#xff0c;不进行任何读写 文件打开 open函数&#xff…

Hibernate(Spring Data)抓取策略

文章目录 示例代码放到最后&#xff0c;使用的是Springboot 项目1. 简介2. Hibernate抓取策略分类2.1 即时加载&#xff08;Eager Loading&#xff09;2.2 延迟加载&#xff08;Lazy Loading&#xff09;2.3 子查询加载&#xff08;Subselect Loading&#xff09;2.4 基于批处理…

排序之选择排序

文章目录 前言一、直接选择排序1、直接选择排序基本思想2、直接选择排序代码实现3、直接选择排序的效率 二、堆排序1、堆排序2、堆排序的效率 前言 选择排序的基本思想就是每一次从待排序的数据元素中选出最小(或最大)的一个元素&#xff0c;存放在序列的起始位置&#xff0c;…

pdfh5在线预览pdf文件

前言 pc浏览器和ios的浏览器都可以直接在线显示pdf文件&#xff0c;但是android浏览器不能在线预览pdf文件&#xff0c;如何预览pdf文件&#xff1f; Github: https://github.com/gjTool/pdfh5 Gitee: https://gitee.com/gjTool/pdfh5 使用pdfh5预览pdf 编写预览页面 <…

PSP - 蛋白质结构预测 OpenFold Multimer 模型训练参数与配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132575709 OpenFold Multimer 是用于预测蛋白质多聚体结构的计算方法。基于OpenFold 的单体预测框架&#xff0c;利用深度学习技术&#xff0c;结…

Python Flask Web开发二:数据库创建和使用

前言 数据库在 Web 开发中起着至关重要的作用。它不仅提供了数据的持久化存储和管理功能&#xff0c;还支持数据的关联和连接&#xff0c;保证数据的一致性和安全性。通过合理地设计和使用数据库&#xff0c;开发人员可以构建强大、可靠的 Web 应用程序&#xff0c;满足用户的…

Mysql数据库(1)—索引

索引是什么&#xff1f; 索引是帮助MySQL高效获取数据的排好序的数据结构。常见的索引数据结构包括&#xff1a; 二叉树红黑树Hash表B-Tree mysql索引分类 按逻辑结构分类&#xff1a;B tree索引、Hash索引、Full-text索引。按物理存储分类&#xff1a; &#xff08;1&…