feat: 新增配置监听器.

This commit is contained in:
2025-02-03 15:35:52 +08:00
parent 379f5c7032
commit fcc8d359c0
6 changed files with 225 additions and 8 deletions

View File

@@ -3,6 +3,8 @@ package com.serliunx.ddns;
import com.serliunx.ddns.config.CommandLineConfiguration; import com.serliunx.ddns.config.CommandLineConfiguration;
import com.serliunx.ddns.config.Configuration; import com.serliunx.ddns.config.Configuration;
import com.serliunx.ddns.config.PropertiesConfiguration; 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.constant.SystemConstants;
import com.serliunx.ddns.core.context.FileInstanceContext; import com.serliunx.ddns.core.context.FileInstanceContext;
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext; import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
@@ -71,6 +73,9 @@ public final class ManagerLite {
// 系统初始化 // 系统初始化
initSystem(); initSystem();
// 配置监听器初始化
initConfigurationListeners();
// 指令初始化 // 指令初始化
initCommands(); initCommands();
@@ -112,6 +117,16 @@ public final class ManagerLite {
System.exit(0); System.exit(0);
} }
/**
* 配置监听器初始化
*/
private static void initConfigurationListeners() {
// 配置监听器IP更新间隔变动
configuration.addListener(new IpRefreshIntervalListener(systemInitializer.getScheduledProvider()));
// 配置监听器:通知变更
configuration.addListener(new NotificationConfigListener());
}
/** /**
* 指令初始化 * 指令初始化
*/ */

View File

@@ -5,10 +5,10 @@ import com.serliunx.ddns.support.Assert;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.LinkedHashMap; import java.util.*;
import java.util.Map;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; 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 { public abstract class AbstractConfiguration implements Configuration {
/**
* 日志
*/
protected final Logger log = LoggerFactory.getLogger(this.getClass()); protected final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* 配置值存储
*/
protected final Map<String, String> valueMap = new LinkedHashMap<>(16); protected final Map<String, String> valueMap = new LinkedHashMap<>(16);
/**
* 上下文更改锁
*/
protected final Lock contextLock = new ReentrantLock(); 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() {} public AbstractConfiguration() {}
@@ -117,7 +136,16 @@ public abstract class AbstractConfiguration implements Configuration {
contextLock.lock(); contextLock.lock();
if (!valueMap.containsKey(key)) if (!valueMap.containsKey(key))
return false; 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; return true;
} finally { } finally {
contextLock.unlock(); contextLock.unlock();
@@ -128,16 +156,51 @@ public abstract class AbstractConfiguration implements Configuration {
public void modify(String key, Object value, boolean createIfAbsent) { public void modify(String key, Object value, boolean createIfAbsent) {
try { try {
contextLock.lock(); contextLock.lock();
boolean invoke = false;
String oldVal = valueMap.get(key);
String newVal = String.valueOf(value);
if (!valueMap.containsKey(key)) { if (!valueMap.containsKey(key)) {
if (createIfAbsent) if (createIfAbsent) {
valueMap.put(key, String.valueOf(value)); valueMap.put(key, newVal);
} else invoke = true;
valueMap.put(key, String.valueOf(value)); }
} else {
valueMap.put(key, newVal);
invoke = true;
}
if (!invoke)
return;
try {
invokeListeners(key, oldVal, newVal);
} catch (Exception e) {
log.warn("监听器执行出现异常[CIA] => {}", e.getMessage());
}
} finally { } finally {
contextLock.unlock(); 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 @Override
public int getPriority() { public int getPriority() {
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
@@ -177,4 +240,22 @@ public abstract class AbstractConfiguration implements Configuration {
* 载入逻辑 * 载入逻辑
*/ */
protected abstract void load0(); 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);
}
}
} }

View 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;
}

View File

@@ -3,6 +3,7 @@ package com.serliunx.ddns.config;
import com.serliunx.ddns.core.Priority; import com.serliunx.ddns.core.Priority;
import com.serliunx.ddns.core.Refreshable; import com.serliunx.ddns.core.Refreshable;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -119,4 +120,18 @@ public interface Configuration extends Refreshable, Priority {
* @param createIfAbsent 是否在不存在指定键时创建 * @param createIfAbsent 是否在不存在指定键时创建
*/ */
void modify(String key, Object value, boolean createIfAbsent); void modify(String key, Object value, boolean createIfAbsent);
/**
* 添加配置监听器
*
* @param listener 监听器
*/
void addListener(ConfigListener listener);
/**
* 获取所有配置监听器
*
* @return 所有监听器
*/
Map<String, List<ConfigListener>> getListeners();
} }

View File

@@ -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);
}
}

View File

@@ -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);
}
}