动态加载配置文件就是在程序运行的过程中实时监控配置文件的状态,在发生变化时重新加载,而无需停止程序。
这里主要是介绍如何在Java环境中实现动态加载配置文件。
主要参考了博文:java动态加载配置文件。
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.11.0version>
dependency>
load()函数用于加载配置文件;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);
}
}
}
No SLF4J providers were found的错误,这表明程序无法生成可用的Slf4j实例。slf4j-simple的test 删掉,否则在编译的时候不起作用:
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>2.0.0-alpha5version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-simpleartifactId>
<version>2.0.0-alpha5version>
dependency>
的更多说明可以参考博文:Maven中的scope总结。log即可。
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
<scope>providedscope>
dependency>