diff --git a/src/main/java/com/serliunx/ddns/ManagerLite.java b/src/main/java/com/serliunx/ddns/ManagerLite.java index aa90b11..44ac3e7 100644 --- a/src/main/java/com/serliunx/ddns/ManagerLite.java +++ b/src/main/java/com/serliunx/ddns/ManagerLite.java @@ -18,13 +18,13 @@ public final class ManagerLite { init(); } - private static SystemInitializer init() { + private static void init() { SystemInitializer systemInitializer = SystemInitializer .configurer() + .clearCache(false) .configuration(new PropertiesConfiguration(SystemConstants.USER_SETTINGS_PROPERTIES_PATH)) .instanceContext(new FileInstanceContext()) .done(); systemInitializer.refresh(); - return systemInitializer; } } diff --git a/src/main/java/com/serliunx/ddns/support/feign/client/IPAddressClient.java b/src/main/java/com/serliunx/ddns/client/IPAddressClient.java similarity index 86% rename from src/main/java/com/serliunx/ddns/support/feign/client/IPAddressClient.java rename to src/main/java/com/serliunx/ddns/client/IPAddressClient.java index 94e8478..ca86d48 100644 --- a/src/main/java/com/serliunx/ddns/support/feign/client/IPAddressClient.java +++ b/src/main/java/com/serliunx/ddns/client/IPAddressClient.java @@ -1,8 +1,8 @@ -package com.serliunx.ddns.support.feign.client; +package com.serliunx.ddns.client; +import com.serliunx.ddns.client.entity.IPAddressResponse; import com.serliunx.ddns.support.feign.JacksonDecoder; import com.serliunx.ddns.support.feign.JacksonEncoder; -import com.serliunx.ddns.support.feign.client.entity.IPAddressResponse; import feign.Feign; import feign.Logger; import feign.RequestLine; @@ -27,7 +27,7 @@ public interface IPAddressClient { * @return IPAddressResponse */ @RequestLine("GET /json") - IPAddressResponse getIPAddress(); + IPAddressResponse getIPAddress(); static IPAddressClient getInstance() { return Feign.builder() diff --git a/src/main/java/com/serliunx/ddns/support/feign/client/entity/IPAddressResponse.java b/src/main/java/com/serliunx/ddns/client/entity/IPAddressResponse.java similarity index 98% rename from src/main/java/com/serliunx/ddns/support/feign/client/entity/IPAddressResponse.java rename to src/main/java/com/serliunx/ddns/client/entity/IPAddressResponse.java index 2df2b8e..fcd3d67 100644 --- a/src/main/java/com/serliunx/ddns/support/feign/client/entity/IPAddressResponse.java +++ b/src/main/java/com/serliunx/ddns/client/entity/IPAddressResponse.java @@ -1,4 +1,4 @@ -package com.serliunx.ddns.support.feign.client.entity; +package com.serliunx.ddns.client.entity; /** * IP地址查询响应 diff --git a/src/main/java/com/serliunx/ddns/constant/InstanceClasses.java b/src/main/java/com/serliunx/ddns/constant/InstanceClasses.java index 50f04a6..dc482ae 100644 --- a/src/main/java/com/serliunx/ddns/constant/InstanceClasses.java +++ b/src/main/java/com/serliunx/ddns/constant/InstanceClasses.java @@ -14,15 +14,15 @@ import java.util.Map; * @since 2024/5/15 */ public final class InstanceClasses { + private InstanceClasses(){throw new UnsupportedOperationException();} - private static final Map> instanceTypeMap = - new HashMap>() { - { - put(InstanceType.ALI_YUN, AliyunInstance.class); - put(InstanceType.TENCENT_CLOUD, TencentInstance.class); - } - }; + private static final Map> instanceTypeMap = new HashMap<>(); + + static { + instanceTypeMap.put(InstanceType.ALI_YUN, AliyunInstance.class); + instanceTypeMap.put(InstanceType.TENCENT_CLOUD, TencentInstance.class); + } public static Class match(InstanceType type) { return instanceTypeMap.get(type); diff --git a/src/main/java/com/serliunx/ddns/core/context/AbstractInstanceContext.java b/src/main/java/com/serliunx/ddns/core/context/AbstractInstanceContext.java index e1bce03..cdd3605 100644 --- a/src/main/java/com/serliunx/ddns/core/context/AbstractInstanceContext.java +++ b/src/main/java/com/serliunx/ddns/core/context/AbstractInstanceContext.java @@ -25,7 +25,7 @@ import static com.serliunx.ddns.util.InstanceUtils.validateInstance; */ public abstract class AbstractInstanceContext implements InstanceContext, MultipleSourceInstanceContext { - private static final Logger log = LoggerFactory.getLogger(AbstractInstanceContext.class); + private final Logger log = LoggerFactory.getLogger(this.getClass()); private final Set listableInstanceFactories = new HashSet<>(); @@ -63,9 +63,7 @@ public abstract class AbstractInstanceContext implements InstanceContext, Multip Set instances = new HashSet<>(); // 高优先级的实例工厂会覆盖低优先级实例工厂所加载的实例 - listableInstanceFactories.stream() - .sorted() - .forEach(f -> instances.addAll(f.getInstances())); + getSortedListableInstanceFactories().forEach(f -> instances.addAll(f.getInstances())); // 初次载入 cacheInstanceMap = new HashMap<>(instances.stream().collect(Collectors.toMap(Instance::getName, i -> i))); @@ -86,10 +84,11 @@ public abstract class AbstractInstanceContext implements InstanceContext, Multip instanceLock.lock(); String name = instance.getName(); Instance instanceExists = instanceMap.get(name); - if (instanceExists != null) + if (instanceExists != null) { throw new InstanceExistsException("该实例已存在!", name, instanceExists); - else + } else { instanceMap.put(name, instance); + } }catch (Exception e){ throw new RuntimeException(e); }finally { @@ -146,7 +145,7 @@ public abstract class AbstractInstanceContext implements InstanceContext, Multip protected void clearCache() { if (cacheInstanceMap != null && !cacheInstanceMap.isEmpty()){ - int size = cacheInstanceMap.size(); + final int size = cacheInstanceMap.size(); cacheInstanceMap.clear(); // 清理实例工厂的缓存信息 listableInstanceFactories.forEach(Clearable::clear); diff --git a/src/main/java/com/serliunx/ddns/core/context/MultipleSourceInstanceContext.java b/src/main/java/com/serliunx/ddns/core/context/MultipleSourceInstanceContext.java index a739270..6428fb4 100644 --- a/src/main/java/com/serliunx/ddns/core/context/MultipleSourceInstanceContext.java +++ b/src/main/java/com/serliunx/ddns/core/context/MultipleSourceInstanceContext.java @@ -3,7 +3,10 @@ package com.serliunx.ddns.core.context; import com.serliunx.ddns.core.factory.InstanceFactory; import com.serliunx.ddns.core.factory.ListableInstanceFactory; +import java.util.Collections; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /** * 多数据源的实例容器, 将多种实例来源汇聚到一起 @@ -26,4 +29,18 @@ public interface MultipleSourceInstanceContext extends InstanceContext, Listable * @return 实例工厂列表 */ Set getListableInstanceFactories(); + + /** + * 获取当前实例容器下所有实例工厂(已排序) + * @return 已排序的实例工厂 + */ + default List getSortedListableInstanceFactories() { + Set listableInstanceFactories = getListableInstanceFactories(); + if (listableInstanceFactories == null || listableInstanceFactories.isEmpty()) + return Collections.emptyList(); + + return listableInstanceFactories.stream() + .sorted() + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/serliunx/ddns/core/factory/AbstractInstanceFactory.java b/src/main/java/com/serliunx/ddns/core/factory/AbstractInstanceFactory.java index 46ed7ea..365a264 100644 --- a/src/main/java/com/serliunx/ddns/core/factory/AbstractInstanceFactory.java +++ b/src/main/java/com/serliunx/ddns/core/factory/AbstractInstanceFactory.java @@ -74,6 +74,11 @@ public abstract class AbstractInstanceFactory implements InstanceFactory, Listab clear0(); } + @Override + public String toString() { + return getClass().getSimpleName() + "(priority: " + getPriority() + ")"; + } + /** * 交由子类去加载实例信息 * @return 实例信息 diff --git a/src/main/java/com/serliunx/ddns/core/factory/FileInstanceFactory.java b/src/main/java/com/serliunx/ddns/core/factory/FileInstanceFactory.java index 44043b2..e5bd733 100644 --- a/src/main/java/com/serliunx/ddns/core/factory/FileInstanceFactory.java +++ b/src/main/java/com/serliunx/ddns/core/factory/FileInstanceFactory.java @@ -26,6 +26,16 @@ public abstract class FileInstanceFactory extends AbstractInstanceFactory { this.instanceDir = instanceDir; } + @Override + public int getPriority() { + return 256; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "(instanceDir: " + instanceDir + ", priority: " + getPriority() + ")"; + } + @Override protected Set load() { Set files = loadFiles(); @@ -38,11 +48,6 @@ public abstract class FileInstanceFactory extends AbstractInstanceFactory { return Collections.emptySet(); } - @Override - public int getPriority() { - return 256; - } - /** * 交由具体的子类去加载实例, 比如: json格式的实例信息、xml格式的实例信息 * @param file 文件信息 diff --git a/src/main/java/com/serliunx/ddns/core/factory/YamlFileInstanceFactory.java b/src/main/java/com/serliunx/ddns/core/factory/YamlFileInstanceFactory.java index 4049354..ac55d30 100644 --- a/src/main/java/com/serliunx/ddns/core/factory/YamlFileInstanceFactory.java +++ b/src/main/java/com/serliunx/ddns/core/factory/YamlFileInstanceFactory.java @@ -96,12 +96,14 @@ public class YamlFileInstanceFactory extends FileInstanceFactory { f.set(instance, Enum.valueOf((Class) clazz, (String) value)); continue; } - if (value != null) + if (value != null) { f.set(instance, value); + } } catch (IllegalAccessException e) { throw new RuntimeException(e); + } finally { + f.setAccessible(false); } - f.setAccessible(false); } return instance; } diff --git a/src/main/java/com/serliunx/ddns/core/instance/AbstractInstance.java b/src/main/java/com/serliunx/ddns/core/instance/AbstractInstance.java index 93c861c..f1829f8 100644 --- a/src/main/java/com/serliunx/ddns/core/instance/AbstractInstance.java +++ b/src/main/java/com/serliunx/ddns/core/instance/AbstractInstance.java @@ -23,7 +23,7 @@ import static com.serliunx.ddns.constant.SystemConstants.XML_ROOT_INSTANCE_NAME; @JacksonXmlRootElement(localName = XML_ROOT_INSTANCE_NAME) public abstract class AbstractInstance implements Instance { - private static final Logger log = LoggerFactory.getLogger(AbstractInstance.class); + private final Logger log = LoggerFactory.getLogger(this.getClass()); /** * 实例名称 diff --git a/src/main/java/com/serliunx/ddns/support/Configurer.java b/src/main/java/com/serliunx/ddns/support/Configurer.java index 7fe6ce1..11ccc63 100644 --- a/src/main/java/com/serliunx/ddns/support/Configurer.java +++ b/src/main/java/com/serliunx/ddns/support/Configurer.java @@ -14,6 +14,7 @@ public final class Configurer { private Configuration configuration; private MultipleSourceInstanceContext instanceContext; + private boolean clearCache; Configurer(){} @@ -29,8 +30,13 @@ public final class Configurer { return this; } + public Configurer clearCache(boolean clearCache) { + this.clearCache = clearCache; + return this; + } + public SystemInitializer done() { Assert.notNull(configuration, instanceContext); - return new SystemInitializer(configuration, instanceContext); + return new SystemInitializer(configuration, instanceContext, clearCache); } } diff --git a/src/main/java/com/serliunx/ddns/support/NetworkContextHolder.java b/src/main/java/com/serliunx/ddns/support/NetworkContextHolder.java index baa6ca0..a7ca1b1 100644 --- a/src/main/java/com/serliunx/ddns/support/NetworkContextHolder.java +++ b/src/main/java/com/serliunx/ddns/support/NetworkContextHolder.java @@ -39,8 +39,9 @@ public final class NetworkContextHolder { } public static String getIpAddress() { - if(IP_ADDRESS != null) + if(IP_ADDRESS != null) { return IP_ADDRESS; + } try { if(!IP_CONTEXT_WAIT_LATCH.await(IP_CONTEXT_TIME_OUT, TimeUnit.SECONDS)) { log.error("IP地址获取超时."); diff --git a/src/main/java/com/serliunx/ddns/support/SystemInitializer.java b/src/main/java/com/serliunx/ddns/support/SystemInitializer.java index fc993eb..23bac2d 100644 --- a/src/main/java/com/serliunx/ddns/support/SystemInitializer.java +++ b/src/main/java/com/serliunx/ddns/support/SystemInitializer.java @@ -6,8 +6,8 @@ import com.serliunx.ddns.core.Clearable; import com.serliunx.ddns.core.Refreshable; import com.serliunx.ddns.core.context.MultipleSourceInstanceContext; import com.serliunx.ddns.core.instance.Instance; -import com.serliunx.ddns.support.feign.client.IPAddressClient; -import com.serliunx.ddns.support.feign.client.entity.IPAddressResponse; +import com.serliunx.ddns.client.IPAddressClient; +import com.serliunx.ddns.client.entity.IPAddressResponse; import com.serliunx.ddns.thread.TaskThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,14 +40,20 @@ public final class SystemInitializer implements Refreshable, Clearable { private final Configuration configuration; private final MultipleSourceInstanceContext instanceContext; + private final boolean clearCache; private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; private Set instances; private final Map> runningInstances = new HashMap<>(64); - SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext) { + SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext, boolean clearCache) { this.configuration = configuration; this.instanceContext = instanceContext; + this.clearCache = clearCache; + } + + SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext) { + this(configuration, instanceContext, true); } public static Configurer configurer() { @@ -80,8 +86,10 @@ public final class SystemInitializer implements Refreshable, Clearable { // 运行实例 runInstances(); - // 实例提交后, 清理实例、配置缓存, 因为读取一次就不需要了 - clear(); + // 清理实例、配置缓存, 正常情况下读取一次就不需要了 + if (clearCache) { + clear(); + } log.info("初始化完成!"); InstanceContextHolder.clearAdditional(); } @@ -120,8 +128,9 @@ public final class SystemInitializer implements Refreshable, Clearable { byte[] buffer = new byte[1024]; int bytesRead; if (inputStream != null) { - while ((bytesRead = inputStream.read(buffer)) != -1) + while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); + } } outputStream.close(); } catch (Exception e) { @@ -140,7 +149,7 @@ public final class SystemInitializer implements Refreshable, Clearable { } // 初始化实例 i.refresh(); - ScheduledFuture future = scheduledThreadPoolExecutor.scheduleWithFixedDelay(i, 0, + ScheduledFuture future = scheduledThreadPoolExecutor.scheduleWithFixedDelay(i, 5, i.getInterval(), TimeUnit.SECONDS); runningInstances.put(i.getName(), future); log.info("{}({})已启动, 运行周期 {} 秒.", i.getName(), i.getType(), i.getInterval()); @@ -187,15 +196,15 @@ public final class SystemInitializer implements Refreshable, Clearable { boolean result = scheduledThreadPoolExecutor.awaitTermination(5, TimeUnit.SECONDS); if (result) { log.error("线程池无法在正常的时间范围内关闭, 将强制关闭线程池!"); - if (!scheduledThreadPoolExecutor.isShutdown()) + if (!scheduledThreadPoolExecutor.isShutdown()) { scheduledThreadPoolExecutor.shutdownNow(); + } } } catch (InterruptedException e) { throw new RuntimeException(e); - } - - instances.clear(); - - runningInstances.clear(); + } finally { + instances.clear(); + runningInstances.clear(); + } } } diff --git a/src/test/java/com/serliunx/ddns/test/ContextTest.java b/src/test/java/com/serliunx/ddns/test/ContextTest.java index 87d5f97..850993c 100644 --- a/src/test/java/com/serliunx/ddns/test/ContextTest.java +++ b/src/test/java/com/serliunx/ddns/test/ContextTest.java @@ -34,9 +34,8 @@ public class ContextTest { @Test public void testFileContext(){ - MultipleSourceInstanceContext context = new FileInstanceContext(); - - context.getInstances().forEach(System.out::println); + FileInstanceContext context = new FileInstanceContext(); + context.getSortedListableInstanceFactories().forEach(System.out::println); } @Test diff --git a/src/test/java/com/serliunx/ddns/test/FactoryTest.java b/src/test/java/com/serliunx/ddns/test/FactoryTest.java index f53bec9..353778a 100644 --- a/src/test/java/com/serliunx/ddns/test/FactoryTest.java +++ b/src/test/java/com/serliunx/ddns/test/FactoryTest.java @@ -1,9 +1,15 @@ package com.serliunx.ddns.test; +import com.serliunx.ddns.constant.InstanceType; import com.serliunx.ddns.constant.SystemConstants; +import com.serliunx.ddns.core.factory.InstanceFactory; +import com.serliunx.ddns.core.factory.ListableInstanceFactory; import com.serliunx.ddns.core.factory.YamlFileInstanceFactory; +import com.serliunx.ddns.core.instance.Instance; import org.junit.Test; +import java.util.Map; + /** * @author SerLiunx * @since 1.0 @@ -12,9 +18,14 @@ public class FactoryTest { @Test public void testYamlFileFactory() { - YamlFileInstanceFactory factory = new YamlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR); + ListableInstanceFactory factory = new YamlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR); factory.refresh(); factory.getInstances().forEach(System.out::println); - factory.clear(); + + Map instances = factory.getInstanceOfType(InstanceType.TENCENT_CLOUD); + + instances.forEach((k, v) -> { + System.out.println(k + ": " + v); + }); } } diff --git a/src/test/java/com/serliunx/ddns/test/support/ClientTest.java b/src/test/java/com/serliunx/ddns/test/support/ClientTest.java index 161fdc7..e4dd4b1 100644 --- a/src/test/java/com/serliunx/ddns/test/support/ClientTest.java +++ b/src/test/java/com/serliunx/ddns/test/support/ClientTest.java @@ -1,6 +1,6 @@ package com.serliunx.ddns.test.support; -import com.serliunx.ddns.support.feign.client.IPAddressClient; +import com.serliunx.ddns.client.IPAddressClient; import org.junit.Test; /**