SpringBoot部署后通过代码修改配置文件并加载

就是项目运行时动态修改yam文件并加载,具体原理不懂,百度拼来的,只给实现方法

首先是依赖以及版本

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>2.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>

        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.28</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

yml配置文件

management:
  health:
    redis:
      enabled: false #关闭对redis的自动检查,这个可以忽略
  endpoints:
    web:
      exposure:
        include: refresh #开放修改端口(网上说的我也不知道啥意思)
elasticsearch:
  password: 123456 #用来测试的数据

配置类
配合配置文件达到动态修改的目的

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author tj
 * @apiNote
 * @date 2021/8/30
 */
@Data
@Component
@ConfigurationProperties(prefix="elasticsearch")
public class ESConfig {

    private String host;
    private int port;
    private String user;
    private String password;

    // ... 省略getter() setter()
}

测试类:通过页面修改配置

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.yaml.snakeyaml.Yaml;

import java.io.FileInputStream;
import java.io.*;
import java.io.IOException;
import java.util.Map;

/**
 * @author tj
 * @apiNote
 * @date 2021/8/30
 */
@RestController
public class EsUserController {

    @Qualifier("legacyContextRefresher")
    @Autowired
    private ContextRefresher contextRefresher;

    @Autowired
    private ESConfig esConfig;

    @GetMapping("/api/refresh/{value}")
    public void refresh(@PathVariable String value) throws IOException {
        // 修改配置文件
        updateYamlFile(value);
        // 刷新配置文件
        //contextRefresher.refresh();
        // 使用刷新后的配置
        System.out.print(esConfig.getPassword());
    }

    public void updateYamlFile(String value) throws IOException {
        String src = EsUserController.class.getClassLoader().getResource("application.yml").getPath();
        //String src = "src/main/resources/application.yml";
        Yaml yaml = new Yaml();
        FileWriter fileWriter;
        FileInputStream fileInputStream = new FileInputStream(new File(src));
        Map<String, Object> yamlMap = yaml.load(fileInputStream);
        Map<String, Object> esMap = (Map<String, Object>) yamlMap.get("elasticsearch");
        esMap.put("password", value);
        //字符输出
        fileWriter = new FileWriter(new File(src));
        //用yaml方法把map结构格式化为yaml文件结构
        fileWriter.write(yaml.dumpAsMap(yamlMap));
        //刷新
        fileWriter.flush();
        //关闭流
        fileWriter.close();
        fileInputStream.close();
        new Thread(() ->contextRefresher.refresh()).start();
    }
}

另一个测试类,来验证结果

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author tj
 * @apiNote
 * @date 2021/8/30
 */
@RestController
public class TestB {

    @Value("${elasticsearch.password}")
    private String password;

    @RequestMapping("/test2")
    public String test2 (){

        return this.password;
    }

}

启动项目,通过页面访问 http://localhost:8080/test2
可以看到返回了我们配置文件中的值

image.png

elasticsearch:
  password: 123456 #用来测试的数据

此时访问 http://localhost:8080/api/refresh/9992323

然后再次访问 http://localhost:8080/test2

image.png

可以发现 这个password的值已经变成了我们想要的值
查看项目中的文件

原文件:
image.png

部署文件:
image.png

成功的修改了部署文件中的值,证明这个方法是可行的

缺点:

修改完成之后加载配置文件相当于项目重新启动了一次,中间会出现短暂服务不能访问的情况,慎用!
建议配合redis或者数据库等中间件使用,无需加载。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容