我想为我的应用程序构建一个ApplicationSetting
。 ApplicationSetting
可以存储在属性文件或数据库表中。设置存储在键值对中。 E.g。
ftp.host = blade
ftp.username = dummy
ftp.pass = pass
content.row_pagination = 20
content.title = How to train your dragon.
我的设计如下:
应用程序设置阅读器:
interface IApplicationSettingReader {
Map read();
}
DatabaseApplicationSettingReader implements IApplicationSettingReader {
dao appSettingDao;
Map read() {
List<AppSettingEntity> listEntity = appSettingsDao.findAll();
Map<String, String> map = new HaspMap<String, String>();
foreach (AppSettingEntity entity : listEntity) {
map.put(entity.getConfigName(), entity.getConfigValue());
}
return new AppSettings(map);
}
}
DatabaseApplicationSettingReader implements IApplicationSettingReader {
dao appSettingDao;
Map read() {
//read from some properties file
return new AppSettings(map);
}
}
应用程序设置类:
AppSettings {
private static AppSettings instance = new AppSettings();
private Map map;
private AppSettings() {
}
public static AppSettings getInstance() {
if (instance == null) {
throw new RuntimeException("Object not configure yet");
}
return instance;
}
public static configure(IApplicationSettingReader reader) {
this.map = reader.read();
}
public String getFtpSetting(String param) {
return map.get("ftp." + param);
}
public String getContentSetting(String param) {
return map.get("content." + param);
}
}
测试类:
AppSettingsTest {
IApplicationSettingReader reader;
@Before
public void setUp() throws Exception {
reader = new DatabaseApplicationSettingReader();
}
@Test
public void getContentSetting_should_get_content_title() {
AppSettings.configure(reader);
Instance settings = AppSettings.getInstance();
String title = settings.getContentSetting("title");
assertNotNull(title);
Sysout(title);
}
}
我的问题是:
你能否就我的代码发表意见,有什么不对吗?????
我配置了一次应用程序设置,在应用程序启动时,我使用适当的阅读器(DbReader
或PropertiesReader
)配置应用程序设置,我将其设为单例,因为应用程序只有一个ApplicationSettngs的实例。问题是,当某些用户直接将数据库或文件编辑到数据库或文件时,我无法获得更改的值。现在,我想实现像ApplicationSettingChangeListener
这样的东西。因此,如果数据发生变化,我将刷新我的应用程序设置。你有什么建议可以实现吗????
答案 0 :(得分:0)
我没有彻底检查过您的代码,但似乎存在并发问题。地图是线程不安全的(HashMap),所以如果你通过config()改变它并让其他线程访问map,你就会遇到问题。
虽然您可以使用ConcurrentHashMap
代替HashMap
,但ConcurrentHashMap
上的批处理操作不是原子的。这意味着,如果您使用它,您将看到“中途”修改配置。根据您的应用程序,这可能不会好。
所以,解决方法就是使用它:
private volatile ImmutableMap map;
public config(){
ImmutableMap newMap = createNewMap();
this.map = newMap;
}
这将原子地改变你的配置(没有中间状态可见)。
至于动态更新配置,log4j使用监视配置文件的后台线程来完成。您当然可以通过定期轮询来监视数据库表。
在这种情况下,您的Config类最好有一个ScheduledExecutor,其任务将监视文件/ db并定期调用config()。
答案 1 :(得分:0)
问题#2的答案是使用一个线程并定期检查文件是否已更改,或者只是使用文件内容重新初始化您的设置。