feat: 新增配置监听器.
This commit is contained in:
@@ -3,6 +3,8 @@ package com.serliunx.ddns;
|
||||
import com.serliunx.ddns.config.CommandLineConfiguration;
|
||||
import com.serliunx.ddns.config.Configuration;
|
||||
import com.serliunx.ddns.config.PropertiesConfiguration;
|
||||
import com.serliunx.ddns.config.listener.IpRefreshIntervalListener;
|
||||
import com.serliunx.ddns.config.listener.NotificationConfigListener;
|
||||
import com.serliunx.ddns.constant.SystemConstants;
|
||||
import com.serliunx.ddns.core.context.FileInstanceContext;
|
||||
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
|
||||
@@ -71,6 +73,9 @@ public final class ManagerLite {
|
||||
// 系统初始化
|
||||
initSystem();
|
||||
|
||||
// 配置监听器初始化
|
||||
initConfigurationListeners();
|
||||
|
||||
// 指令初始化
|
||||
initCommands();
|
||||
|
||||
@@ -112,6 +117,16 @@ public final class ManagerLite {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置监听器初始化
|
||||
*/
|
||||
private static void initConfigurationListeners() {
|
||||
// 配置监听器:IP更新间隔变动
|
||||
configuration.addListener(new IpRefreshIntervalListener(systemInitializer.getScheduledProvider()));
|
||||
// 配置监听器:通知变更
|
||||
configuration.addListener(new NotificationConfigListener());
|
||||
}
|
||||
|
||||
/**
|
||||
* 指令初始化
|
||||
*/
|
||||
|
||||
@@ -5,10 +5,10 @@ import com.serliunx.ddns.support.Assert;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 配置信息的抽象实现, 定义公共逻辑
|
||||
@@ -19,9 +19,28 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public abstract class AbstractConfiguration implements Configuration {
|
||||
|
||||
/**
|
||||
* 日志
|
||||
*/
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
/**
|
||||
* 配置值存储
|
||||
*/
|
||||
protected final Map<String, String> valueMap = new LinkedHashMap<>(16);
|
||||
/**
|
||||
* 上下文更改锁
|
||||
*/
|
||||
protected final Lock contextLock = new ReentrantLock();
|
||||
/**
|
||||
* 监听器
|
||||
* <li> 仅初始化时做增删改操作.
|
||||
*/
|
||||
protected final Map<String, List<ConfigListener>> listeners = new HashMap<>(16);
|
||||
|
||||
/**
|
||||
* 监听所有配置键的监听器标识符
|
||||
*/
|
||||
public static final String ALL_KEYS_LISTENERS_TAG = "ALL_KEYS_LISTENERS_TAG";
|
||||
|
||||
public AbstractConfiguration() {}
|
||||
|
||||
@@ -117,7 +136,16 @@ public abstract class AbstractConfiguration implements Configuration {
|
||||
contextLock.lock();
|
||||
if (!valueMap.containsKey(key))
|
||||
return false;
|
||||
valueMap.put(key, String.valueOf(value));
|
||||
String oldVal = valueMap.get(key);
|
||||
String newVal = String.valueOf(value);
|
||||
valueMap.put(key, newVal);
|
||||
|
||||
try {
|
||||
invokeListeners(key, oldVal, newVal);
|
||||
} catch (Exception e) {
|
||||
log.warn("监听器执行出现异常 => {}", e.getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
contextLock.unlock();
|
||||
@@ -128,16 +156,51 @@ public abstract class AbstractConfiguration implements Configuration {
|
||||
public void modify(String key, Object value, boolean createIfAbsent) {
|
||||
try {
|
||||
contextLock.lock();
|
||||
boolean invoke = false;
|
||||
String oldVal = valueMap.get(key);
|
||||
String newVal = String.valueOf(value);
|
||||
if (!valueMap.containsKey(key)) {
|
||||
if (createIfAbsent)
|
||||
valueMap.put(key, String.valueOf(value));
|
||||
} else
|
||||
valueMap.put(key, String.valueOf(value));
|
||||
if (createIfAbsent) {
|
||||
valueMap.put(key, newVal);
|
||||
invoke = true;
|
||||
}
|
||||
} else {
|
||||
valueMap.put(key, newVal);
|
||||
invoke = true;
|
||||
}
|
||||
|
||||
if (!invoke)
|
||||
return;
|
||||
try {
|
||||
invokeListeners(key, oldVal, newVal);
|
||||
} catch (Exception e) {
|
||||
log.warn("监听器执行出现异常[CIA] => {}", e.getMessage());
|
||||
}
|
||||
} finally {
|
||||
contextLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(ConfigListener listener) {
|
||||
Collection<String> keys = listener.interestedIn();
|
||||
Assert.notNull(keys);
|
||||
if (keys.isEmpty()) {
|
||||
listeners.computeIfAbsent(ALL_KEYS_LISTENERS_TAG, key -> new ArrayList<>())
|
||||
.add(listener);
|
||||
} else {
|
||||
keys.forEach(k -> {
|
||||
listeners.computeIfAbsent(k, k1 -> new ArrayList<>())
|
||||
.add(listener);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<ConfigListener>> getListeners() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return Integer.MAX_VALUE;
|
||||
@@ -177,4 +240,22 @@ public abstract class AbstractConfiguration implements Configuration {
|
||||
* 载入逻辑
|
||||
*/
|
||||
protected abstract void load0();
|
||||
|
||||
/**
|
||||
* 触发监听器
|
||||
*/
|
||||
private void invokeListeners(String key, Object oldVal, Object newVal) throws Exception {
|
||||
// 触发监听了所有配置项的监听器
|
||||
List<ConfigListener> all = listeners.get(ALL_KEYS_LISTENERS_TAG);
|
||||
for (ConfigListener cl : all) {
|
||||
cl.onChanged(this, key, oldVal, newVal);
|
||||
}
|
||||
// 触发其他监听器
|
||||
List<ConfigListener> listenerList = listeners.get(key);
|
||||
if (listenerList == null || listenerList.isEmpty())
|
||||
return;
|
||||
for (ConfigListener cl : listenerList) {
|
||||
cl.onChanged(this, key, oldVal, newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
src/main/java/com/serliunx/ddns/config/ConfigListener.java
Normal file
36
src/main/java/com/serliunx/ddns/config/ConfigListener.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.serliunx.ddns.config;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 配置监听器
|
||||
* <li> 针对配置的变动所需要执行的逻辑
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.4
|
||||
* @since 2025/2/3
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ConfigListener {
|
||||
|
||||
/**
|
||||
* 指定当前监听器所感兴趣的配置项(可多个)
|
||||
* <li> 为空时即监听所有配置项
|
||||
*
|
||||
* @return 感兴趣的配置项
|
||||
*/
|
||||
default Collection<String> interestedIn() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置项发生了变动的回调
|
||||
*
|
||||
* @param configuration 配置
|
||||
* @param key 配置键
|
||||
* @param oldVal 旧值
|
||||
* @param newVal 新值
|
||||
*/
|
||||
void onChanged(Configuration configuration, String key, Object oldVal, Object newVal) throws Exception;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.serliunx.ddns.config;
|
||||
import com.serliunx.ddns.core.Priority;
|
||||
import com.serliunx.ddns.core.Refreshable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -119,4 +120,18 @@ public interface Configuration extends Refreshable, Priority {
|
||||
* @param createIfAbsent 是否在不存在指定键时创建
|
||||
*/
|
||||
void modify(String key, Object value, boolean createIfAbsent);
|
||||
|
||||
/**
|
||||
* 添加配置监听器
|
||||
*
|
||||
* @param listener 监听器
|
||||
*/
|
||||
void addListener(ConfigListener listener);
|
||||
|
||||
/**
|
||||
* 获取所有配置监听器
|
||||
*
|
||||
* @return 所有监听器
|
||||
*/
|
||||
Map<String, List<ConfigListener>> getListeners();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.serliunx.ddns.config.listener;
|
||||
|
||||
import com.serliunx.ddns.config.ConfigListener;
|
||||
import com.serliunx.ddns.config.Configuration;
|
||||
import com.serliunx.ddns.constant.ConfigurationKeys;
|
||||
import com.serliunx.ddns.support.Assert;
|
||||
import com.serliunx.ddns.support.ipprovider.ScheduledProvider;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 配置监听器:IP更新间隔变动
|
||||
* <li> 刷新间隔发生变更时通知定时器结束并重新开始计时.
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.4
|
||||
* @since 2025/2/3
|
||||
*/
|
||||
public final class IpRefreshIntervalListener implements ConfigListener {
|
||||
|
||||
private final ScheduledProvider scheduledProvider;
|
||||
|
||||
public IpRefreshIntervalListener(ScheduledProvider scheduledProvider) {
|
||||
Assert.notNull(scheduledProvider);
|
||||
this.scheduledProvider = scheduledProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> interestedIn() {
|
||||
return Collections.singletonList(ConfigurationKeys.KEY_TASK_REFRESH_INTERVAL_IP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(Configuration configuration, String key, Object oldVal, Object newVal) throws Exception {
|
||||
if (key == null
|
||||
|| !key.equals(ConfigurationKeys.KEY_TASK_REFRESH_INTERVAL_IP)
|
||||
|| oldVal == null
|
||||
|| newVal == null
|
||||
|| oldVal.equals(newVal))
|
||||
return;
|
||||
Long newInterval = configuration.getLong(ConfigurationKeys.KEY_TASK_REFRESH_INTERVAL_IP);
|
||||
scheduledProvider.changeTimePeriod(newInterval);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.serliunx.ddns.config.listener;
|
||||
|
||||
import com.serliunx.ddns.config.ConfigListener;
|
||||
import com.serliunx.ddns.config.Configuration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 配置监听器:通知变更
|
||||
* <li> 仅输出变更信息
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.4
|
||||
* @since 2025/2/3
|
||||
*/
|
||||
public final class NotificationConfigListener implements ConfigListener {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NotificationConfigListener.class);
|
||||
|
||||
@Override
|
||||
public void onChanged(Configuration configuration, String key, Object oldVal, Object newVal) throws Exception {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("配置更新: 配置项 {} 由 {} 调整至 {}", key, oldVal, newVal);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user