java实现两种方式自动刷新读取配置文件,本文代码已经上传到gitee,以如下的有两个属性的简单配置文件为例
name=hzj
age=18
手动书写配置文件刷新逻辑
使用定时任务+AtomicRerence
实现配置文件刷新
package com.shoothzj.man;
import java.io.File;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
public class ConfigReaderMan {
private final String path;
private final AtomicReference<Properties> confRef = new AtomicReference<>();
private final ScheduledExecutorService executor;
public ConfigReaderMan(String path, int period, TimeUnit timeUnit) {
this.path = path;
loadConf();
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleWithFixedDelay(this::loadConf, period, period, timeUnit);
}
private void loadConf() {
try {
Properties conf = new Properties();
conf.load(new File(path).toURI().toURL().openStream());
confRef.set(conf);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String getName() {
return confRef.get().getProperty("name");
}
public int getAge() {
return Integer.parseInt(confRef.get().getProperty("age"));
}
public void close() {
executor.shutdown();
}
}
对应测试用例如下
package com.shoothzj.cc2;
import org.assertj.core.util.Files;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.util.concurrent.TimeUnit;
class ConfigReaderCc2Test {
@Test
public void testReloadConfig() {
File file = Files.newTemporaryFile();
file.deleteOnExit();
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write("name=hzj\n".getBytes());
fos.write("age=18\n".getBytes());
} catch (Exception e) {
Assertions.fail(e.getMessage());
}
ConfigReaderCc2 reader = new ConfigReaderCc2(file.getAbsolutePath(), 1, TimeUnit.MILLISECONDS);
Assertions.assertEquals("hzj", reader.getName());
Assertions.assertEquals(18, reader.getAge());
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write("name=jzh\n".getBytes());
fos.write("age=81\n".getBytes());
fos.flush();
} catch (Exception e) {
Assertions.fail(e.getMessage());
}
// sleep five seconds to make sure the config file is reloaded
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
Assertions.fail(e.getMessage());
}
Assertions.assertEquals("jzh", reader.getName());
Assertions.assertEquals(81, reader.getAge());
reader.close();
}
}
使用commons-configuration2
+AtomicReference
实现配置文件刷新
package com.shoothzj.cc2;
import org.apache.commons.configuration2.BaseConfiguration;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;
import java.io.File;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
public class ConfigReaderCc2 {
private final AtomicReference<Configuration> confRef = new AtomicReference<>();
private final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder = new ReloadingFileBasedConfigurationBuilder<>(PropertiesConfiguration.class);
private final PeriodicReloadingTrigger trigger;
public ConfigReaderCc2(String path, int period, TimeUnit timeUnit) {
Parameters parameters = new Parameters();
builder.configure(parameters.fileBased().setFile(new File(path)));
builder.addEventListener(ConfigurationBuilderEvent.RESET, event -> {
System.out.println("config.properties has been reloaded");
confRef.set(loadConf());
});
trigger = new PeriodicReloadingTrigger(builder.getReloadingController(), null, period, timeUnit);
trigger.start();
confRef.set(loadConf());
}
private Configuration loadConf() {
try {
return builder.getConfiguration();
} catch (ConfigurationException e) {
System.err.println("load configuration failed " + e);
return new BaseConfiguration();
}
}
public String getName() {
return confRef.get().getString("name");
}
public int getAge() {
return confRef.get().getInt("age");
}
public void close() {
trigger.shutdown();
}
}
对应测试用例如下
package com.shoothzj.man;
import org.assertj.core.util.Files;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.util.concurrent.TimeUnit;
class ConfigReaderManTest {
@Test
public void testReloadConfig() {
File file = Files.newTemporaryFile();
file.deleteOnExit();
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write("name=hzj\n".getBytes());
fos.write("age=18\n".getBytes());
} catch (Exception e) {
Assertions.fail(e.getMessage());
}
ConfigReaderMan reader = new ConfigReaderMan(file.getAbsolutePath(), 1, TimeUnit.MILLISECONDS);
Assertions.assertEquals("hzj", reader.getName());
Assertions.assertEquals(18, reader.getAge());
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write("name=jzh\n".getBytes());
fos.write("age=81\n".getBytes());
fos.flush();
} catch (Exception e) {
Assertions.fail(e.getMessage());
}
// sleep five seconds to make sure the config file is reloaded
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
Assertions.fail(e.getMessage());
}
Assertions.assertEquals("jzh", reader.getName());
Assertions.assertEquals(81, reader.getAge());
reader.close();
}
}