java實(shí)現(xiàn)兩種方式自動(dòng)刷新讀取配置文件,本文代碼已經(jīng)上傳到gitee,以如下的有兩個(gè)屬性的簡(jiǎn)單配置文件為例
name=hzj
age=18
手動(dòng)書(shū)寫(xiě)配置文件刷新邏輯
使用定時(shí)任務(wù)+AtomicRerence實(shí)現(xiàn)配置文件刷新
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();
}
}
對(duì)應(yīng)測(cè)試用例如下
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實(shí)現(xiàn)配置文件刷新
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();
}
}
對(duì)應(yīng)測(cè)試用例如下
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();
}
}