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,刷新文件配置项生效!


相关推荐
liangbo739 分钟前
01-JVM 内存模型全景
java·jvm
橘子编程40 分钟前
Java邮件发送全攻略:从入门到实战
java·开发语言·spring boot·spring·spring cloud·maven
阿哉43 分钟前
一次 Lombok 静默失效排查:JDK 23 注解处理默认策略变更引发的满屏「找不到符号」
java
纪伊路上盛名在44 分钟前
了解一点Docker
java·docker·容器
掘金者阿豪1 小时前
Let‘s Encrypt 证书到底会不会自动续期?从一次服务器迁移后的证书排查说起
后端
码农阿豪1 小时前
Seedance 2.0/2.5 虚拟素材能跨 Key 共用吗?一次讲清 Asset ID、账号隔离与 SaaS 素材架构
java·运维·架构
Meta391 小时前
Java八股文之Spring Boot中解决Redis和MySQL的数据一致性问题
java·spring boot·redis
joinwell521 小时前
Agent 中断后,原任务如何安全接管?从恢复标记到效果事实
人工智能·后端·架构
sp421 小时前
羽量级的 Java Bean 实体校验器
后端
魔兽大山哥1 小时前
【NL2SQL 实战 07】LIMIT 不是小事:默认 100 行背后的产品判断
后端