SpringBoot支持动态更新配置文件参数

前言

博主介绍:✌目前全网粉丝3W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。

涵盖技术内容:Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。

博主所有博客文件目录索引:博客目录索引(持续更新)

视频平台:b站-Coder长路

章节描述

在springboot服务启动之后,想要通过接口来动态修改配置文件参数,实现动态参数配置信息获取。

gitee:https://gitee.com/changluJava/demo-exer/tree/master/SpringBoot/springboot-config/src/main/java/com/changlu/springbootconfig

github:https://github.com/changluya/Java-Demos/tree/master/SpringBoot/springboot-config/src/main/java/com/changlu/springbootconfig

实现接口动态刷新配置参数

代码实现

1、DynamicPropertyUpdater(动态配置项更新器)

自定义DynamicPropertySource动态配置类,接着本质通过environment.getPropertySources()来获取到配置项属性器,后续更新配置项去构造DynamicPropertySource添加到属性器即可完成属性配置覆盖。

java 复制代码
package com.changlu.springbootconfig.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class DynamicPropertyUpdater {

   private static final Logger logger = LoggerFactory.getLogger(DynamicPropertyUpdater.class);

   private final ConfigurableEnvironment environment;

   public DynamicPropertyUpdater(ConfigurableEnvironment environment) {
       this.environment = environment;
   }

   /**
    * 动态更新 Environment 中的配置项值
    *
    * @param key   配置项的键
    * @param value 配置项的新值
    */
   public void updateProperty(String key, String value) {
       logger.info("Updating property: {} = {}", key, value);
       MutablePropertySources propertySources = environment.getPropertySources();
       // 添加或更新属性
       propertySources.addFirst(new DynamicPropertySource(key, value));
   }

   /**
    * 批量动态更新 Environment 中的配置项值
    * @param properties 配置项
    */
   public void updateProperties(Map<String, String> properties) {
       for (Map.Entry<String, String> entry : properties.entrySet()) {
           // 复用单独更新配置项逻辑
           this.updateProperty(entry.getKey(), entry.getValue());
       }
   }

   /**
    * 自定义动态属性源
    */
   private static class DynamicPropertySource extends PropertySource<String> {

       private final String key;
       private final String value;

       public DynamicPropertySource(String key, String value) {
           super("dynamicPropertySource"); // 属性源的名称
           this.key = key;
           this.value = value;
       }

       @Override
       public Object getProperty(String name) {
           // 如果传入的 key 匹配,则返回对应的 value
           if (key.equals(name)) {
               return value;
           }
           return null; // 如果不匹配,返回 null
       }
   }
}

2、EnvironmentContext(environment管理器)

java 复制代码
package com.changlu.springbootconfig.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class EnvironmentContext {

    @Autowired
    private Environment environment;

    public String getProperty(String key, String defaultVal) {
        return environment.getProperty(key, defaultVal);
    }
}

3、ConfigController 实现查询配置、更新配置接口

java 复制代码
import com.changlu.springbootconfig.config.DynamicPropertyUpdater;
import com.changlu.springbootconfig.config.EnvironmentContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/config")
public class ConfigController {

    @Autowired
    private DynamicPropertyUpdater dynamicPropertyUpdater;

    @Autowired
    private EnvironmentContext environmentContext;

    /**
     * 动态更新配置项的值
     *
     * @param key   配置项的键
     * @param value 配置项的新值
     * @return 更新结果
     */
    @PostMapping("/update")
    public String updateConfig(@RequestParam String key, @RequestParam String value) {
        dynamicPropertyUpdater.updateProperty(key, value);
        return "Config updated successfully: " + key + " = " + value;
    }

    /**
     * 根据 key 获取配置项的值
     *
     * @param key 配置项的键
     * @return 配置项的值
     */
    @GetMapping("/get")
    public String getConfig(@RequestParam String key) {
        String value = environmentContext.getProperty(key, "未找到对应的配置项");
        return key + " = " + value;
    }

}

测试

首先在application.properties配置文件中补充一个参数配置:

properties 复制代码
server.port=8080
changlu.param=parm1

1)启动服务后,查询下参数信息:changlu.param

正常获取到结果值parm1。

2)接着我们调用update更新参数接口

更新changlu.param参数值为:789

3)此时我们再次查询下该参数:

当前已经得到了最新的参数值为:789


实现刷新当前使用的配置文件

目的

在真实场景下,我们会直接上到服务器上修改配置文件参数,接着想要通过调用接口重新加载该配置文件中的所有参数配置信息。

动作:修改配置文件参数项。

发起:调用/refresh接口实现动态刷新。

代码实现

1、SystemPropertyUtil (实现自定义conf配置路径user.dir.conf )

实际场景中,我们的配置文件不会直接打包在jar包中,通常会指定一个配置文件路径。

SystemPropertyUtil:

java 复制代码
import java.io.File;

public class SystemPropertyUtil {

    public static void setSystemUserDir() {
        String dir = System.getProperty("user.dir");
        String conf = String.format("%s/%s", dir, "conf");
        File file = new File(conf);
        if(!file.exists()) {
            dir = dir.substring(0, dir.lastIndexOf("/"));
            conf = String.format("%s/%s", dir, "conf");
            file = new File(conf);
            if(file.exists()) {
                System.setProperty("user.dir", dir);
            }
        }
        System.setProperty("user.dir.conf", System.getProperty("user.dir") + "/conf");
    }
}

接着在启动器服务运行前调用方法来设置全局变量参数user.dir.conf:

java 复制代码
SystemPropertyUtil.setSystemUserDir();

此时我们的配置文件在当前工程目录下的conf中:

配置参数值如下:

properties 复制代码
server.port=8756
changlu.test=444

2、ConfigFileReloader(实现配置文件加载器)

在加载器中,实现了一个方法会去读取user.dir.conf这个变量路径值,此时得到的是/conf的全路径,接着我们去补充配置文件名application.properties即可:

ConfigFileReloader.java

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.stereotype.Component;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

@Component
public class ConfigFileReloader {

    private final ConfigurableEnvironment environment;

    @Autowired
    public ConfigFileReloader(ConfigurableEnvironment environment) {
        this.environment = environment;
    }

    /**
     * 重新加载配置文件
     *
     * @throws IOException 如果文件读取失败
     */
    public void reloadConfig() throws IOException {
        Properties properties = new Properties();
        try (FileInputStream fis = new FileInputStream(System.getProperty("user.dir.conf") + "/application.properties")) {
            properties.load(fis);
        }

        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.addFirst(new PropertiesPropertySource("dynamicConfig", properties));
    }
}

3、EnvironmentContext 指定默认读取配置文件路径参数

补充属性源读取路径信息:PropertySource注解中读取静态变量对应conf路径下application.properties

java 复制代码
@Component
@PropertySource(value = "file:${user.dir.conf}/application.properties")
public class EnvironmentContext {

4、实现刷新配置文件参数接口

java 复制代码
@Autowired
private ConfigFileReloader configFileReloader;

/**
 * 刷新配置文件
 *
 * @return 配置项的值
 */
@GetMapping("/refresh")
public String refreshConfig() throws IOException {
    configFileReloader.reloadConfig();
    return "success";
}

后续步骤就是,我们修改conf下的配置文件参数值,然后调用下生效参数接口即可刷新当前应用服务的配置信息。


测试

确认好配置信息:

接着我们启动服务,来调用下获取参数配置信息接口:正常读取到parm1

接着我们手动将配置文件参数修改:

接着调用刷新配置文件接口:

成功刷新,此时我们再去读取下该配置信息:

当前读取到的配置参数为parm2,刷新文件配置项生效!


相关推荐
Ekreke5 小时前
一次Nginx 403 的问题排查
后端
没有bug.的程序员5 小时前
电商系统分布式架构实战:从单体到微服务的演进之路
java·分布式·微服务·云原生·架构·监控体系·指标采集
Query*5 小时前
Java 设计模式——代理模式:从静态代理到 Spring AOP 最优实现
java·设计模式·代理模式
梵得儿SHI5 小时前
Java 反射机制深度解析:从对象创建到私有成员操作
java·开发语言·class对象·java反射机制·操作类成员·三大典型·反射的核心api
JAVA学习通5 小时前
Spring AI 核心概念
java·人工智能·spring·springai
望获linux5 小时前
【实时Linux实战系列】实时 Linux 在边缘计算网关中的应用
java·linux·服务器·前端·数据库·操作系统
绝无仅有5 小时前
面试真实经历某商银行大厂数据库MYSQL问题和答案总结(二)
后端·面试·github
绝无仅有5 小时前
通过编写修复脚本修复 Docker 启动失败(二)
后端·面试·github
..Cherry..5 小时前
【java】jvm
java·开发语言·jvm
老K的Java兵器库5 小时前
并发集合踩坑现场:ConcurrentHashMap size() 阻塞、HashSet 并发 add 丢数据、Queue 伪共享
java·后端·spring