springboot 实现动态刷新配置的详细过程

 更新时间:2023年05月29日 14:39:40   作者:lfsun666  
这篇文章主要介绍了springboot实现动态刷新配置,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

自定义的配置数据源,继承自Spring框架的 MapPropertySource 类

从一个名为 my.properties 的文件中读取配置信息,并在每10秒钟刷新一次。

这里不加@Component,是因为:
FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
// 属性源是按照添加的顺序进行合并的,后添加的属性源中的属性会覆盖前面添加的属性源中的同名属性。
// 因此,为了确保我们自定义的属性源中的属性优先级最高,我们需要将它添加到属性源列表的最后。这样就能保证后添加的属性源中的属性值会覆盖之前的同名属性。
environment.getPropertySources().addLast(filePropertiesSource);

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.MapPropertySource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
/**
 *
 * 自定义的配置数据源,继承自Spring框架的 MapPropertySource 类,从一个名为 my.properties 的文件中读取配置信息,并在每10秒钟刷新一次。
 * @author Administrator
 */
@Slf4j
//@Component
public class FilePropertiesSource extends MapPropertySource {
    private static final Logger logger = LoggerFactory.getLogger(FilePropertiesSource.class);
    private static final String CONFIG_FILE_NAME = "my.properties";
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public FilePropertiesSource() {
        super("filePropertiesSource", new HashMap<>());
    }
    /**
     * 从配置文件中读取配置,10s 更新一次
     */
    @PostConstruct
    @Scheduled(fixedRate = 10_000)
    public void refreshSource() throws IOException {
        logger.info("开始读取配置文件 {}", CONFIG_FILE_NAME);
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE_NAME);
        if (inputStream == null) {
            throw new FileNotFoundException("配置文件 " + CONFIG_FILE_NAME + " 不存在");
        }
        Map<String, String> newProperties = new HashMap<>();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (StringUtils.isEmpty(line) || line.startsWith("#")) {
                    continue;
                }
                String[] pair = StringUtils.split(line, "=");
                if (pair == null || pair.length != 2) {
                    logger.warn("忽略配置项 {}", line);
                    continue;
                }
                String key = pair[0].trim();
                String value = pair[1].trim();
                logger.debug("读取配置项 {} = {}", key, value);
                newProperties.put(key, value);
            }
        } catch (IOException e) {
            logger.error("读取配置文件 {} 出现异常:{}", CONFIG_FILE_NAME, e.getMessage(), e);
            throw e;
        }
        synchronized (this) {
            source.clear();
            source.putAll(newProperties);
        }
        logger.info("读取配置文件完成,共读取 {} 个配置项,时间 {}", newProperties.size(), LocalDateTime.now().format(DATE_TIME_FORMATTER));
    }
    /**
     * 覆盖 getProperty 方法,实现实时获取配置
     *
     * @param key 配置项的 key
     * @return 配置项的值
     */
    @Override
    public Object getProperty(String key) {
        return source.get(key);
    }
}

定义一个Spring配置类,定义了一个名为 filePropertiesSource 的Bean,并将其加入到环境变量中。

import com.lfsun.bootdynamicenv.config.FilePropertiesSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
/**
 * 一个Spring配置类,定义了一个名为 filePropertiesSource 的Bean,并将其加入到环境变量中。
 */
@Configuration
public class AutoConfig {
    @Bean
    public FilePropertiesSource filePropertiesSource(ConfigurableEnvironment environment) {
        FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
        // 属性源是按照添加的顺序进行合并的,后添加的属性源中的属性会覆盖前面添加的属性源中的同名属性。
        // 因此,为了确保我们自定义的属性源中的属性优先级最高,我们需要将它添加到属性源列表的最后。这样就能保证后添加的属性源中的属性值会覆盖之前的同名属性。
        environment.getPropertySources().addLast(filePropertiesSource);
        return filePropertiesSource;
    }
}

为了方便直接用启动类作为控制层

@DependsOn(“filePropertiesSource”) 依赖于filePropertiesSource,以实现刷新配置。
@EnableScheduling 实现定时刷新
private String userName; 会被计算机名称覆盖,计算机名称优先级最高

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@DependsOn("filePropertiesSource")
@EnableScheduling
@RestController
@SpringBootApplication
public class Application {
    @Autowired
    private Environment environment;
    @Value("${user-name}")
    private String userName;
    @GetMapping(path = "get")
    public String getProperty(String key) {
        return userName + "  |  " + environment.getProperty(key);
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

实现效果

访问:http://localhost:8080/get?key=my-user-id

可见修改user-name无效,被计算机名称所覆盖。
这时候修改my-user-id=

再访问:http://localhost:8080/get?key=my-user-id

已实现刷新:

ext:

@PostConstruct:

用于指定在依赖注入完成后需要执行的初始化方法。具体来说,当Spring容器完成对一个bean的依赖注入后,会调用该bean中使用了@PostConstruct注解的方法。

例如,如果在一个类中定义了一个方法,并在该方法上添加了@PostConstruct注解,那么当Spring容器初始化该类时,会自动调用该方法,以完成一些必要的初始化操作。

@PostConstruct注解的方法不能带有任何参数,也不能有返回值,因为Spring不会使用这些返回值。如果需要返回一些状态信息,可以使用类成员变量来保存这些信息。另外需要注意的是,@PostConstruct注解只能用于非静态方法。

@Scheduled(fixedRate = 10_000)

@Scheduled是一个Spring框架提供的注解,用于实现基于时间的任务调度。通过在方法上添加@Scheduled注解,并指定相应的属性,可以使得该方法在指定的时间间隔内自动执行。

例如,@Scheduled(fixedRate = 10_000)表示每隔10秒执行一次该方法。fixedRate属性指定了执行方法的时间间隔,单位为毫秒。除此之外,还可以使用cron表达式指定执行时间,如@Scheduled(cron = “0 0 12 * * ?”)表示每天中午12点执行一次该方法。

需要注意的是,使用@Scheduled注解的方法必须是无参方法,且返回类型为void或Future。如果需要传递参数或返回结果,可以使用实例变量或方法返回值进行传递。同时,为了使得@Scheduled注解生效,需要在启动类上面@EnableScheduling

到此这篇关于springboot 实现动态刷新配置的文章就介绍到这了,更多相关springboot动态刷新配置内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot解析JSON数据的三种方案

    SpringBoot解析JSON数据的三种方案

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,本文给大家介绍了SpringBoot解析JSON数据的三种方案,需要的朋友可以参考下
    2024-03-03
  • 四个Java必须知道的负载均衡算法分享

    四个Java必须知道的负载均衡算法分享

    我们在设计系统的时候,为了系统的高扩展性,会创建无状态的系统。但是,要使系统具有更好的可扩展性,除了无状态设计之外,还要考虑采用什么负载均衡算法,本文就带领大家认识以下常见的4种负载均衡算法
    2023-01-01
  • java使用JSCH实现SFTP文件管理

    java使用JSCH实现SFTP文件管理

    这篇文章主要为大家详细介绍了java使用JSCH实现SFTP文件管理,实现上传、下载等功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • Springboot 接口对接文件及对象的操作方法

    Springboot 接口对接文件及对象的操作方法

    这篇文章主要介绍了Springboot 接口对接文件及对象的操作,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • 在idea中为注释标记作者日期操作

    在idea中为注释标记作者日期操作

    这篇文章主要介绍了在idea中为注释标记作者日期操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Spring Boot通过Junit实现单元测试过程解析

    Spring Boot通过Junit实现单元测试过程解析

    这篇文章主要介绍了Spring Boot通过Junit实现单元测试过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • jdk21环境配置详细步骤记录

    jdk21环境配置详细步骤记录

    JDK是整个Java开发的核心,它包含了Java的运行环境和Java工具,这篇文章主要给大家介绍了关于jdk21环境配置的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • Spring避免循环依赖的策略详解

    Spring避免循环依赖的策略详解

    在Spring框架中,循环依赖是指两个或多个bean相互依赖对方,形成一个闭环,这在应用启动时可能导致BeanCurrentlyInCreationException异常,本文给大家介绍了Spring中如何避免循环依赖,需要的朋友可以参考下
    2024-02-02
  • Spring Cloud Alibaba Nacos服务治理平台服务注册、RestTemplate实现微服务之间访问负载均衡访问的问题

    Spring Cloud Alibaba Nacos服务治理平台服务注册、RestTemplate实现微服务之间访

    这篇文章主要介绍了Spring Cloud Alibaba:Nacos服务治理平台,服务注册、RestTemplate实现微服务之间访问,负载均衡访问,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • Spring Boot2.0中SpringWebContext找不到无法使用的解决方法

    Spring Boot2.0中SpringWebContext找不到无法使用的解决方法

    这篇文章主要给大家介绍了关于Spring Boot2.0中SpringWebContext找不到无法使用的解决方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-12-12

最新评论