java动态配置工具类(DynamicConfigUtils)

在现代微服务或分布式系统中,动态配置管理是一项非常重要的功能,它允许我们在不重启服务的情况下,动态地更新配置项(如数据库连接、API限流配置、日志级别等)。在Java中,可以通过多种方式实现动态配置管理,包括使用配置中心(如Apollo、Nacos、Consul等)或本地的动态配置刷新机制。

我们将实现一个 DynamicConfigUtils 工具类,用于支持动态配置的加载和更新。工具类提供以下功能:

  1. 动态加载配置:从文件或配置中心加载配置。
  2. 监听配置更新:当配置文件发生变化时自动更新应用中的配置项。
  3. 手动刷新配置:支持手动调用刷新配置项。
  4. 配置缓存:将已加载的配置缓存到内存中,避免频繁读取外部文件。

一、工具类结构设计

我们将 DynamicConfigUtils 设计为单例模式,以确保配置的全局统一性。工具类将包含以下核心方法:

  1. loadConfig():加载初始配置。
  2. getConfig():获取配置项的值。
  3. setConfig():动态设置或更新配置项的值。
  4. refreshConfig():手动刷新或监听外部变动来刷新配置。

二、DynamicConfigUtils 实现

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class DynamicConfigUtils {

    private static DynamicConfigUtils instance;
    private final Map<String, String> configCache = new HashMap<>();
    private final String configFilePath;
    private WatchService watchService;

    /**
     * 构造方法,传入配置文件路径
     *
     * @param configFilePath 配置文件路径
     */
    private DynamicConfigUtils(String configFilePath) {
        this.configFilePath = configFilePath;
        loadConfig();
        startConfigFileWatcher();
    }

    /**
     * 获取单例实例
     *
     * @param configFilePath 配置文件路径
     * @return DynamicConfigUtils实例
     */
    public static synchronized DynamicConfigUtils getInstance(String configFilePath) {
        if (instance == null) {
            instance = new DynamicConfigUtils(configFilePath);
        }
        return instance;
    }

    /**
     * 加载配置文件,并将配置项缓存到内存中
     */
    private void loadConfig() {
        try (FileInputStream inputStream = new FileInputStream(configFilePath)) {
            Properties properties = new Properties();
            properties.load(inputStream);
            for (String key : properties.stringPropertyNames()) {
                configCache.put(key, properties.getProperty(key));
            }
            System.out.println("配置文件加载完成:" + configCache);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取指定配置项的值
     *
     * @param key 配置项的键
     * @return 配置项的值
     */
    public String getConfig(String key) {
        return configCache.get(key);
    }

    /**
     * 动态设置配置项的值
     *
     * @param key   配置项的键
     * @param value 配置项的值
     */
    public void setConfig(String key, String value) {
        configCache.put(key, value);
        System.out.println("动态设置配置项:" + key + " = " + value);
    }

    /**
     * 手动刷新配置文件,重新加载配置项
     */
    public void refreshConfig() {
        System.out.println("手动刷新配置文件...");
        loadConfig();
    }

    /**
     * 开启配置文件监视器,自动监听配置文件变化并刷新配置
     */
    private void startConfigFileWatcher() {
        try {
            watchService = FileSystems.getDefault().newWatchService();
            Path path = Paths.get(configFilePath).getParent();
            path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);

            Thread watchThread = new Thread(() -> {
                while (true) {
                    try {
                        WatchKey key = watchService.take();
                        for (WatchEvent<?> event : key.pollEvents()) {
                            if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                                Path changed = (Path) event.context();
                                if (changed.endsWith(Paths.get(configFilePath).getFileName())) {
                                    System.out.println("配置文件已修改,重新加载配置...");
                                    loadConfig();
                                }
                            }
                        }
                        key.reset();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            });
            watchThread.setDaemon(true);
            watchThread.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭文件监视器,释放资源
     */
    public void close() {
        try {
            if (watchService != null) {
                watchService.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试方法,模拟配置文件的加载和更新
     */
    public static void main(String[] args) throws InterruptedException {
        // 配置文件路径
        String configFilePath = "config.properties";

        // 获取配置工具类实例并加载配置
        DynamicConfigUtils configUtils = DynamicConfigUtils.getInstance(configFilePath);
        System.out.println("当前配置项:key1 = " + configUtils.getConfig("key1"));

        // 动态设置一个配置项
        configUtils.setConfig("key2", "new_value");
        System.out.println("当前配置项:key2 = " + configUtils.getConfig("key2"));

        // 模拟手动刷新配置文件
        Thread.sleep(5000);
        configUtils.refreshConfig();
    }
}

三、功能详解

1. 单例模式

为了确保动态配置工具类在应用程序中的全局统一性,我们采用单例模式实现,通过 getInstance() 方法来获取唯一的 DynamicConfigUtils 实例。

public static synchronized DynamicConfigUtils getInstance(String configFilePath) {
    if (instance == null) {
        instance = new DynamicConfigUtils(configFilePath);
    }
    return instance;
}
2. 配置文件加载

loadConfig() 方法会读取配置文件,并将配置项缓存到 configCache(一个 HashMap 对象)中,确保配置在内存中可以快速读取。

private void loadConfig() {
    try (FileInputStream inputStream = new FileInputStream(configFilePath)) {
        Properties properties = new Properties();
        properties.load(inputStream);
        for (String key : properties.stringPropertyNames()) {
            configCache.put(key, properties.getProperty(key));
        }
        System.out.println("配置文件加载完成:" + configCache);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
3. 动态获取与设置配置项

getConfig() 方法用于从缓存中获取指定的配置项值,setConfig() 方法用于动态设置或更新配置项,并将其保存到内存中。

public String getConfig(String key) {
    return configCache.get(key);
}

public void setConfig(String key, String value) {
    configCache.put(key, value);
    System.out.println("动态设置配置项:" + key + " = " + value);
}
4. 配置文件监控

通过 WatchService 机制,我们可以监控配置文件的变动。一旦文件发生修改(ENTRY_MODIFY 事件),工具类会自动重新加载配置。

private void startConfigFileWatcher() {
    try {
        watchService = FileSystems.getDefault().newWatchService();
        Path path = Paths.get(configFilePath).getParent();
        path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);

        Thread watchThread = new Thread(() -> {
            while (true) {
                try {
                    WatchKey key = watchService.take();
                    for (WatchEvent<?> event : key.pollEvents()) {
                        if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                            Path changed = (Path) event.context();
                            if (changed.endsWith(Paths.get(configFilePath).getFileName())) {
                                System.out.println("配置文件已修改,重新加载配置...");
                                loadConfig();
                            }
                        }
                    }
                    key.reset();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
        watchThread.setDaemon(true);
        watchThread.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
5. 手动刷新配置

除了监听文件变化,工具类还提供了手动刷新配置的功能,通过 refreshConfig() 方法可以手动触发配置的重新加载。

public void refreshConfig() {
    System.out.println("手动刷新配置文件...");
    loadConfig();
}

四、使用示例

  1. 准备一个 config.properties 配置文件,内容如下:
key1=value1
key2=value2
  1. 运行 main() 方法,加载配置文件并打印内容。随后可以手动更新配置文件,工具类会

自动检测到修改并重新加载。

public static void main(String[] args) throws InterruptedException {
    String configFilePath = "config.properties";

    DynamicConfigUtils configUtils = DynamicConfigUtils.getInstance(configFilePath);
    System.out.println("当前配置项:key1 = " + configUtils.getConfig("key1"));

    configUtils.setConfig("key2", "new_value");
    System.out.println("当前配置项:key2 = " + configUtils.getConfig("key2"));

    Thread.sleep(5000);
    configUtils.refreshConfig();
}

五、功能扩展建议

  1. 外部配置中心:可以通过集成Nacos、Apollo等配置中心实现分布式系统的统一配置管理。
  2. 缓存持久化:当配置发生变化时,可以将更新的配置持久化到本地文件或数据库。
  3. 配置监听器:为每个配置项提供监听器,当配置项发生变化时,自动通知相应的服务或模块更新。

六、总结

DynamicConfigUtils是一个Java动态配置工具类,用于在运行时动态配置应用程序的参数和属性。

该工具类提供了一系列静态方法,用于读取和设置配置文件中的参数和属性。可以通过指定配置文件的路径,读取配置文件中的键值对,并将其作为Map返回。也可以根据指定的键获取配置文件中对应的值。

除了读取配置文件,DynamicConfigUtils还提供了设置配置文件的方法。可以指定配置文件的路径和一组键值对,将这些键值对写入到配置文件中。

该工具类还提供了一些实用的方法,例如判断配置文件是否存在,判断配置文件中是否存在某个键等。

DynamicConfigUtils可以方便地读取和设置配置文件中的参数和属性,使得应用程序在运行时可以灵活地进行配置和调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Flying_Fish_Xuan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值