IDEA04:动态加载配置文件

写在前面

  • 动态加载配置文件就是在程序运行的过程中实时监控配置文件的状态,在发生变化时重新加载,而无需停止程序。

  • 这里主要是介绍如何在Java环境中实现动态加载配置文件。

  • 主要参考了博文:java动态加载配置文件

一、引入依赖包

  • commons-io主要是用于实现文件更改的监控。
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.11.0</version>
</dependency>

二、配置配置文件

三、程序demo

  • JSON文件的解析用的是fastjson库;
  • load()函数用于加载配置文件;
  • 监听程序用了线程,这样可以避免阻塞主线程;
  • 记录到的配置项使用HashMap来保存,方便使用;
  • getConfig()函数来返回读到内存中的配置;
  • 注意load()getConfig()均对同一个变量进行操作,需要加锁。

程序如下:

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;

@Slf4j
public class DynamicConfig implements Runnable {

    // 指定文件名及相关路径
    private String filename = "config.properties";

    private String rootDir = System.getProperty("root.dir", System.getProperty("user.dir"));

    private String filePath = rootDir + File.separator + filename;

    // 用HashMap存放配置
    private HashMap<Integer, String> config = new HashMap<>();;

    public DynamicConfig() {
        // 使用默认配置文件路径
    }

    public DynamicConfig(String filePath) {
        // 使用传入的配置文件路径覆盖默认路径
        this.filePath = filePath;
    }

    // 返回config,已加锁
    public synchronized HashMap<Integer, String> getConfig() {
        return config;
    }

    // 加载配置文件更新config,已加锁
    private synchronized void load() {
        File file = new File(filePath);
        if (!file.exists()) {
            log.warn("File is not exist. file: {}", file.getAbsolutePath());
            return;
        }
        File configFile = new File(filePath);
        try {
            // 清空HashMap
            config.clear();

            // 加载配置文件
            String configContent = FileUtils.readFileToString(configFile, "UTF-8");
            JSONObject configJson = JSON.parseObject(configContent);

            log.info("Load config, file: {}", file.getAbsolutePath());
            // 打印当前加载的配置
            JSONArray  patterns = configJson.getJSONArray("patterns");
            for(int i=0;i<patterns.size();i++)
            {
                JSONObject pattern = patterns.getJSONObject(i);
                // 解析配置数组内容
                int pattern_id = pattern.getInteger("pattern_id");
                String method = pattern.getString("method");
                System.out.println(String.valueOf(pattern_id) + ":" + method);

                // 记录到HashMap
                config.put(pattern_id, method);
            }
        } catch (IOException e) {
            log.error("Load config error.", e);
        }
    }

    @Override
    public void run() {
        // 文件变动监听,监听的是这个目录
        FileAlterationObserver observer = new FileAlterationObserver(rootDir);
        observer.addListener(new FileAlterationListenerAdaptor() {
            @Override
            public void onFileCreate(File file) {
                // 当指定的文件创建的时候
                if (filename.equals(file.getName())) {
                    log.info("Config file create. file: {}", file.getAbsolutePath());
                    load();
                }
            }

            @Override
            public void onFileChange(File file) {
                // 当指定的文件修改的时候
                if (filename.equals(file.getName())) {
                    log.info("Config file change. file: {}", file.getAbsolutePath());
                    load();
                }
            }

            @Override
            public void onFileDelete(File file) {
                // 当指定的文件删除
                if (filename.equals(file.getName())) {
                    log.info("Config file delete file: {}", file.getAbsolutePath());
                }
            }
        });
        observer.checkAndNotify();
        FileAlterationMonitor monitor = new FileAlterationMonitor();
        monitor.addObserver(observer);
        try {
            monitor.start();
            log.info("Start file change monitor. Path: {}", rootDir);
        } catch (Exception e) {
            log.error("Init file change error.", e);
        }
    }
}

四、一些报错

1. SLF4J: No SLF4J providers were found.

  • 场景
  • 程序一开始运行时,在控制台输出报错。
  • 程序能够正常运行,但无法输出日志。
  • 原因
  • Slf4j可以看作是Log4j的标准接口,它本身不包含实现。
  • 因此Maven如果配置不当,很容易出现No SLF4J providers were found的错误,这表明程序无法生成可用的Slf4j实例。
  • 解决方法
  • 参考博客:SLF4J 报错解决:No SLF4J providers were found
  • Maven依赖需要配置两个包,如果是从https://mvnrepository.com/直接拷贝的话,需要把slf4j-simple<scope>test</scope>删掉,否则在编译的时候不起作用:
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>2.0.0-alpha5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-simple</artifactId>
	<version>2.0.0-alpha5</version>
</dependency>
  • 关于<scope>的更多说明可以参考博文:Maven中的scope总结
  • 另外,实现@Slf4j注解可以避免每次写日志时都需要使用日志对象,直接用log即可。
  • @Slf4j注解需要Lombok插件,Maven配置如下:
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.24</version>
	<scope>provided</scope>
</dependency>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值