@@ -35,4 +35,9 @@ public final class ConfigurationKeys {
|
|||||||
* http请求超时时间(秒)
|
* http请求超时时间(秒)
|
||||||
*/
|
*/
|
||||||
public static final String KEY_HTTP_OVERTIME = "system.http.overtime";
|
public static final String KEY_HTTP_OVERTIME = "system.http.overtime";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip地址提供器类型
|
||||||
|
*/
|
||||||
|
public static final String KEY_IP_PROVIDER_TYPE = "system.ip.provider.type";
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/main/java/com/serliunx/ddns/constant/IpProviderType.java
Normal file
32
src/main/java/com/serliunx/ddns/constant/IpProviderType.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package com.serliunx.ddns.constant;
|
||||||
|
|
||||||
|
import com.serliunx.ddns.support.ipprovider.IpApiProvider;
|
||||||
|
import com.serliunx.ddns.support.ipprovider.Provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip供应器类型
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||||
|
* @version 1.0.3
|
||||||
|
* @since 2024/11/25
|
||||||
|
*/
|
||||||
|
public enum IpProviderType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip数据提供商 <a href="https://ip-api.com/">ip-api</a>
|
||||||
|
* <li> 国外的数据, 国内访问不稳定.
|
||||||
|
*/
|
||||||
|
IP_API(new IpApiProvider()),
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final Provider provider;
|
||||||
|
|
||||||
|
IpProviderType(Provider provider) {
|
||||||
|
this.provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Provider getProvider() {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ public final class Assert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void notNull(Object object, String msg) {
|
public static void notNull(Object object, String msg) {
|
||||||
if(object == null) {
|
if (object == null) {
|
||||||
throw new NullPointerException(msg);
|
throw new NullPointerException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,12 @@ public final class Assert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void isLargerThan(int source, int target) {
|
public static void isLargerThan(int source, int target) {
|
||||||
|
if (source <= target) {
|
||||||
|
throw new IllegalArgumentException(String.format("%s太小了, 它必须大于%s", source, target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void isLargerThan(long source, long target) {
|
||||||
if(source <= target) {
|
if(source <= target) {
|
||||||
throw new IllegalArgumentException(String.format("%s太小了, 它必须大于%s", source, target));
|
throw new IllegalArgumentException(String.format("%s太小了, 它必须大于%s", source, target));
|
||||||
}
|
}
|
||||||
@@ -43,13 +49,13 @@ public final class Assert {
|
|||||||
|
|
||||||
public static void notEmpty(Collection<?> collection) {
|
public static void notEmpty(Collection<?> collection) {
|
||||||
notNull(collection);
|
notNull(collection);
|
||||||
if(collection.isEmpty())
|
if (collection.isEmpty())
|
||||||
throw new IllegalArgumentException("参数不能为空!");
|
throw new IllegalArgumentException("参数不能为空!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void notEmpty(CharSequence charSequence) {
|
public static void notEmpty(CharSequence charSequence) {
|
||||||
notNull(charSequence);
|
notNull(charSequence);
|
||||||
if(charSequence.length() == 0)
|
if (charSequence.length() == 0)
|
||||||
throw new IllegalArgumentException("参数不能为空!");
|
throw new IllegalArgumentException("参数不能为空!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
package com.serliunx.ddns.support;
|
package com.serliunx.ddns.support;
|
||||||
|
|
||||||
import com.serliunx.ddns.config.Configuration;
|
import com.serliunx.ddns.config.Configuration;
|
||||||
|
import com.serliunx.ddns.config.ConfigurationKeys;
|
||||||
|
import com.serliunx.ddns.constant.IpProviderType;
|
||||||
import com.serliunx.ddns.constant.SystemConstants;
|
import com.serliunx.ddns.constant.SystemConstants;
|
||||||
import com.serliunx.ddns.core.Clearable;
|
import com.serliunx.ddns.core.Clearable;
|
||||||
import com.serliunx.ddns.core.Refreshable;
|
import com.serliunx.ddns.core.Refreshable;
|
||||||
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
|
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
|
||||||
import com.serliunx.ddns.core.instance.Instance;
|
import com.serliunx.ddns.core.instance.Instance;
|
||||||
|
import com.serliunx.ddns.support.ipprovider.IpApiProvider;
|
||||||
|
import com.serliunx.ddns.support.ipprovider.Provider;
|
||||||
|
import com.serliunx.ddns.support.ipprovider.ScheduledProvider;
|
||||||
import com.serliunx.ddns.support.okhttp.IPAddressResponse;
|
import com.serliunx.ddns.support.okhttp.IPAddressResponse;
|
||||||
import com.serliunx.ddns.support.okhttp.HttpClient;
|
import com.serliunx.ddns.support.okhttp.HttpClient;
|
||||||
import com.serliunx.ddns.thread.TaskThreadFactory;
|
import com.serliunx.ddns.thread.TaskThreadFactory;
|
||||||
@@ -46,6 +51,7 @@ public final class SystemInitializer implements Refreshable, Clearable {
|
|||||||
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
|
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
|
||||||
private Set<Instance> instances;
|
private Set<Instance> instances;
|
||||||
private final Map<String, ScheduledFuture<?>> runningInstances = new HashMap<>(64);
|
private final Map<String, ScheduledFuture<?>> runningInstances = new HashMap<>(64);
|
||||||
|
private ScheduledProvider scheduledProvider;
|
||||||
|
|
||||||
SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext, boolean clearCache) {
|
SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext, boolean clearCache) {
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
@@ -79,6 +85,9 @@ public final class SystemInitializer implements Refreshable, Clearable {
|
|||||||
// 获取核心线程数量, 默认为CPU核心数量
|
// 获取核心线程数量, 默认为CPU核心数量
|
||||||
int coreSize = configuration.getInteger(KEY_THREAD_POOL_CORE_SIZE, Runtime.getRuntime().availableProcessors());
|
int coreSize = configuration.getInteger(KEY_THREAD_POOL_CORE_SIZE, Runtime.getRuntime().availableProcessors());
|
||||||
|
|
||||||
|
// 初始化ip地址更新任务
|
||||||
|
initIpTask();
|
||||||
|
|
||||||
// 初始化线程池
|
// 初始化线程池
|
||||||
initThreadPool(coreSize);
|
initThreadPool(coreSize);
|
||||||
|
|
||||||
@@ -165,20 +174,6 @@ public final class SystemInitializer implements Refreshable, Clearable {
|
|||||||
// 初始化一个线程保活
|
// 初始化一个线程保活
|
||||||
scheduledThreadPoolExecutor.submit(() -> {});
|
scheduledThreadPoolExecutor.submit(() -> {});
|
||||||
|
|
||||||
// 提交定时获取网络IP的定时任务
|
|
||||||
scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
|
|
||||||
InstanceContextHolder.setAdditional("ip-update");
|
|
||||||
log.info("正在尝试获取本机最新的IP地址.");
|
|
||||||
IPAddressResponse response = HttpClient.getIPAddress();
|
|
||||||
String ip;
|
|
||||||
if(response != null
|
|
||||||
&& (ip = response.getQuery()) != null) {
|
|
||||||
NetworkContextHolder.setIpAddress(ip);
|
|
||||||
log.info("本机最新公网IP地址 => {}", ip);
|
|
||||||
}
|
|
||||||
InstanceContextHolder.clearAdditional();
|
|
||||||
}, 0, configuration.getLong(KEY_TASK_REFRESH_INTERVAL_IP, 300L), TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
// 添加进程结束钩子函数
|
// 添加进程结束钩子函数
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
InstanceContextHolder.setAdditional("stopping");
|
InstanceContextHolder.setAdditional("stopping");
|
||||||
@@ -189,6 +184,21 @@ public final class SystemInitializer implements Refreshable, Clearable {
|
|||||||
}, "DDNS-ShutDownHook"));
|
}, "DDNS-ShutDownHook"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initIpTask() {
|
||||||
|
scheduledProvider = new ScheduledProvider(getInternalProvider(),
|
||||||
|
configuration.getLong(KEY_TASK_REFRESH_INTERVAL_IP, 300L));
|
||||||
|
|
||||||
|
scheduledProvider.whenUpdate(ip -> {
|
||||||
|
NetworkContextHolder.setIpAddress(ip);
|
||||||
|
log.info("本机最新公网IP地址 => {}", ip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Provider getInternalProvider() {
|
||||||
|
return configuration.getEnum(IpProviderType.class, ConfigurationKeys.KEY_IP_PROVIDER_TYPE,
|
||||||
|
IpProviderType.IP_API).getProvider();
|
||||||
|
}
|
||||||
|
|
||||||
private void checkAndCloseSafely() {
|
private void checkAndCloseSafely() {
|
||||||
if (scheduledThreadPoolExecutor == null)
|
if (scheduledThreadPoolExecutor == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.serliunx.ddns.support.ipprovider;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抽象的ip提供器, 定义公共逻辑
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||||
|
* @version 1.0.3
|
||||||
|
* @since 2024/11/25
|
||||||
|
*/
|
||||||
|
public abstract class AbstractProvider implements Provider {
|
||||||
|
|
||||||
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行期间总共的ip查询次数
|
||||||
|
*/
|
||||||
|
protected long total;
|
||||||
|
/**
|
||||||
|
* 上次发生的变动的ip地址
|
||||||
|
*/
|
||||||
|
protected String last = null;
|
||||||
|
/**
|
||||||
|
* 缓存的最新ip地址
|
||||||
|
* <li> !!!该地址为上次获得最新地址, 不一定为当前最新的地址
|
||||||
|
*/
|
||||||
|
protected String cache = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCount() {
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLast() {
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
//do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get() {
|
||||||
|
String ipAddress = doGet();
|
||||||
|
if (ipAddress == null) {
|
||||||
|
log.error("ip地址获取失败!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
total++;
|
||||||
|
|
||||||
|
if (cache == null ||
|
||||||
|
!cache.equals(ipAddress)) {
|
||||||
|
last = cache;
|
||||||
|
cache = ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCache() {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取具体的ip地址
|
||||||
|
*/
|
||||||
|
protected abstract String doGet();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.serliunx.ddns.support.ipprovider;
|
||||||
|
|
||||||
|
import com.serliunx.ddns.support.okhttp.HttpClient;
|
||||||
|
import com.serliunx.ddns.support.okhttp.IPAddressResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip数据提供商 <a href="https://ip-api.com/">ip-api</a>
|
||||||
|
* <li> 国外的数据, 国内访问不稳定.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||||
|
* @version 1.0.3
|
||||||
|
* @since 2024/11/25
|
||||||
|
*/
|
||||||
|
public final class IpApiProvider extends AbstractProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doGet() {
|
||||||
|
IPAddressResponse response = HttpClient.getIPAddress();
|
||||||
|
if (response == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return response.getQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.serliunx.ddns.support.ipprovider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip供应器接口定义
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||||
|
* @version 1.0.3
|
||||||
|
* @since 2024/11/25
|
||||||
|
*/
|
||||||
|
public interface Provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取本次运行期间ip的查询次数
|
||||||
|
*
|
||||||
|
* @return 查询次数
|
||||||
|
*/
|
||||||
|
long getCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取上次发生变动的ip地址
|
||||||
|
*
|
||||||
|
* @return 上次发生变动的ip地址
|
||||||
|
*/
|
||||||
|
String getLast();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最新的ip
|
||||||
|
*
|
||||||
|
* @return 最新的ip
|
||||||
|
*/
|
||||||
|
String get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的最新ip地址
|
||||||
|
* <li> !!!该地址为上次获得最新地址, 不一定为当前最新的地址
|
||||||
|
*
|
||||||
|
* @return 缓存的最新ip地址
|
||||||
|
*/
|
||||||
|
String getCache();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package com.serliunx.ddns.support.ipprovider;
|
||||||
|
|
||||||
|
import com.serliunx.ddns.support.Assert;
|
||||||
|
import com.serliunx.ddns.support.InstanceContextHolder;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动更新的ip供应器
|
||||||
|
* <li> 异步更新ip, 获取到的ip地址不一定为最新可用的。
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||||
|
* @version 1.0.3
|
||||||
|
* @since 2024/11/25
|
||||||
|
*/
|
||||||
|
public class ScheduledProvider extends AbstractProvider {
|
||||||
|
|
||||||
|
private final Provider internalProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行周期(秒)
|
||||||
|
*/
|
||||||
|
private volatile long timePeriod;
|
||||||
|
/**
|
||||||
|
* 任务
|
||||||
|
*/
|
||||||
|
private volatile ScheduledFuture<?> task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置线程池
|
||||||
|
*/
|
||||||
|
private ScheduledThreadPoolExecutor poolExecutor = null;
|
||||||
|
/**
|
||||||
|
* 处理器
|
||||||
|
*/
|
||||||
|
private Consumer<String> valueConsumer = null;
|
||||||
|
|
||||||
|
public ScheduledProvider(Provider internalProvider, long timePeriod) {
|
||||||
|
Assert.notNull(internalProvider);
|
||||||
|
Assert.isLargerThan(timePeriod, 0);
|
||||||
|
this.internalProvider = internalProvider;
|
||||||
|
this.timePeriod = timePeriod;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledProvider(Provider internalProvider) {
|
||||||
|
this(internalProvider, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get() {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
poolExecutor = new ScheduledThreadPoolExecutor(2);
|
||||||
|
// 提交
|
||||||
|
submitTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新执行周期
|
||||||
|
* <li> 回替换掉现有的更新任务
|
||||||
|
*
|
||||||
|
* @param timePeriod 新的执行周期
|
||||||
|
*/
|
||||||
|
public void changeTimePeriod(long timePeriod) {
|
||||||
|
Assert.isLargerThan(timePeriod, 0);
|
||||||
|
this.timePeriod = timePeriod;
|
||||||
|
// 取消现有的任务
|
||||||
|
task.cancel(true);
|
||||||
|
submitTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip更新时需要执行的逻辑
|
||||||
|
*
|
||||||
|
* @param valueConsumer 逻辑
|
||||||
|
*/
|
||||||
|
public void whenUpdate(Consumer<String> valueConsumer) {
|
||||||
|
this.valueConsumer = valueConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doGet() {
|
||||||
|
// 不应该执行到这里
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交任务逻辑
|
||||||
|
*/
|
||||||
|
private void submitTask() {
|
||||||
|
task = poolExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
// 打断时, 终止已有的任务. (逻辑上不应该发生)
|
||||||
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
log.debug("上一个ip更新任务已终止.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InstanceContextHolder.setAdditional("ip-update");
|
||||||
|
cache = internalProvider.get();
|
||||||
|
|
||||||
|
if (valueConsumer != null) {
|
||||||
|
valueConsumer.accept(cache);
|
||||||
|
}
|
||||||
|
}, 0, timePeriod, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,9 +26,18 @@ public final class HttpClient {
|
|||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(HttpClient.class);
|
private static final Logger log = LoggerFactory.getLogger(HttpClient.class);
|
||||||
private static final ObjectMapper JSON_MAPPER = new JsonMapper();
|
private static final ObjectMapper JSON_MAPPER = new JsonMapper();
|
||||||
|
private static final int DEFAULT_OVERTIME = 3;
|
||||||
|
|
||||||
private HttpClient() {throw new UnsupportedOperationException();}
|
private HttpClient() {throw new UnsupportedOperationException();}
|
||||||
|
|
||||||
|
static {
|
||||||
|
CLIENT = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(DEFAULT_OVERTIME, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(DEFAULT_OVERTIME, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(DEFAULT_OVERTIME, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取本机的ip地址
|
* 获取本机的ip地址
|
||||||
*
|
*
|
||||||
@@ -63,7 +72,7 @@ public final class HttpClient {
|
|||||||
* @param configuration 配置信息
|
* @param configuration 配置信息
|
||||||
*/
|
*/
|
||||||
public static void init(Configuration configuration) {
|
public static void init(Configuration configuration) {
|
||||||
Integer overtime = configuration.getInteger(ConfigurationKeys.KEY_HTTP_OVERTIME, 3);
|
Integer overtime = configuration.getInteger(ConfigurationKeys.KEY_HTTP_OVERTIME, DEFAULT_OVERTIME);
|
||||||
|
|
||||||
CLIENT = new OkHttpClient.Builder()
|
CLIENT = new OkHttpClient.Builder()
|
||||||
.connectTimeout(overtime, TimeUnit.SECONDS)
|
.connectTimeout(overtime, TimeUnit.SECONDS)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
system.cfg.log.onstart=true
|
system.cfg.log.onstart=true
|
||||||
system.pool.core.size=4
|
system.pool.core.size=4
|
||||||
system.task.refresh.interval.ip=300
|
system.task.refresh.interval.ip=300
|
||||||
instance.aliyun.endpoint.url=alidns.cn-hangzhou.aliyuncs.com
|
system.ip.provider.type=IP_API
|
||||||
system.http.overtime=3
|
system.http.overtime=3
|
||||||
|
instance.aliyun.endpoint.url=alidns.cn-hangzhou.aliyuncs.com
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.serliunx.ddns.test.support;
|
||||||
|
|
||||||
|
import com.serliunx.ddns.support.ipprovider.IpApiProvider;
|
||||||
|
import com.serliunx.ddns.support.ipprovider.Provider;
|
||||||
|
import com.serliunx.ddns.support.ipprovider.ScheduledProvider;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 供应器测试
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||||
|
* @version 1.0.3
|
||||||
|
* @since 2024/11/25
|
||||||
|
*/
|
||||||
|
public class ProviderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIpApiProvider() {
|
||||||
|
Provider provider = new IpApiProvider();
|
||||||
|
System.out.println(provider.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testScheduledProvider() throws Exception {
|
||||||
|
ScheduledProvider provider = new ScheduledProvider(new IpApiProvider(), 3);
|
||||||
|
provider.changeTimePeriod(10);
|
||||||
|
TimeUnit.SECONDS.sleep(60);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user