java动态加载配置文件

前言

 

项目启动时需要从一些配置文件中加载相关配置,在运行过程中,希望修改配置文件的内容,可以重新加载配置。

下面会提供一个基本示例,仅供参考。

示例

引入依赖

需要用到commons-io包:

    <dependencies>
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>
    </dependencies>

java示例

package com.xuxd.demo.file.watch;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;

/**
 * daily-demo.
 *
 * @author xuxd
 * @date 2021-12-09 18:46:30
 **/
@Slf4j
public class AppConfig extends HashMap<String, Object> {

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

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

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

    {
        // 构造对象实例的时候,开启监听并加载配置
        watch();
    }

    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 (InputStream inputStream = new FileInputStream(configFile)) {
            putAll(load(inputStream));
        } catch (Exception e) {
            log.error("Load config error.", e);
        }
        log.info("Load config, file: {}", file.getAbsolutePath());
        // 打印当前加载的配置
        this.forEach((k, v) -> {
            System.out.println(k + "=" + v);
        });
    }

    private Map<? extends String, ?> load(InputStream inputStream) throws IOException {
        Properties properties = new Properties();
        properties.load(inputStream);
        return Collections.unmodifiableMap((Map) properties);
    }

    void watch() {
        // 文件变动监听,监听的是这个目录
        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);
        }
    }

}

说明

关键是示例中watch方法实现,主要就是监听指定目录,内部也是异步线程采用观察者模式实现的。

当该目录下文件变动,回调相应动作,因为这里只处理指定配置文件的变动,实现对配置文件的热加载。

注意,这只是个示例,实际项目上这样肯定不行的,图懒省事我是直接继承Map方法,但是容易触发并发问题(加载配置的时候同时在读取,另外也没有处理删除配置的情况),在实际场景中建议采用装饰器模式和copy on write思想来规避这些问题。

测试

测试代码

public class AppConfigMain {
    public static void main(String[] args) throws InterruptedException {
        new AppConfig();
        Thread.currentThread().join();
    }
}

运行过程中,修改配置:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不识君的荒漠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值