瀏覽代碼

增加 apollo 读取本地 db,需要进一步优化~

YunaiV 4 年之前
父節點
當前提交
17cb37f577
共有 35 個文件被更改,包括 96 次插入1975 次删除
  1. 94 19
      src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java
  2. 0 35
      src/main/java/cn/iocoder/dashboard/framework/apollox/Config.java
  3. 0 19
      src/main/java/cn/iocoder/dashboard/framework/apollox/ConfigChangeListener.java
  4. 0 11
      src/main/java/cn/iocoder/dashboard/framework/apollox/ConfigService.java
  5. 0 23
      src/main/java/cn/iocoder/dashboard/framework/apollox/DefaultConfig.java
  6. 0 14
      src/main/java/cn/iocoder/dashboard/framework/apollox/enums/PropertyChangeType.java
  7. 0 79
      src/main/java/cn/iocoder/dashboard/framework/apollox/internals/AbstractConfigRepository.java
  8. 0 35
      src/main/java/cn/iocoder/dashboard/framework/apollox/internals/ConfigRepository.java
  9. 0 345
      src/main/java/cn/iocoder/dashboard/framework/apollox/internals/RemoteConfigRepository.java
  10. 0 18
      src/main/java/cn/iocoder/dashboard/framework/apollox/internals/RepositoryChangeListener.java
  11. 0 35
      src/main/java/cn/iocoder/dashboard/framework/apollox/model/ConfigChange.java
  12. 0 53
      src/main/java/cn/iocoder/dashboard/framework/apollox/model/ConfigChangeEvent.java
  13. 0 16
      src/main/java/cn/iocoder/dashboard/framework/apollox/package-info.java
  14. 0 61
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloAnnotationProcessor.java
  15. 0 22
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloConfig.java
  16. 0 15
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloConfigChangeListener.java
  17. 0 68
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloProcessor.java
  18. 0 141
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/SpringValueProcessor.java
  19. 0 57
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/boot/ApolloApplicationContextInitializer.java
  20. 0 18
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/boot/ApolloAutoConfiguration.java
  21. 0 49
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/ConfigPropertySource.java
  22. 0 31
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/ConfigPropertySourceFactory.java
  23. 0 47
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/ConfigPropertySourcesProcessor.java
  24. 0 9
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/PropertySourcesConstants.java
  25. 0 159
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/AutoUpdateConfigChangeListener.java
  26. 0 160
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/PlaceholderHelper.java
  27. 0 72
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/PropertySourcesProcessor.java
  28. 0 152
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValue.java
  29. 0 28
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValueDefinition.java
  30. 0 94
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValueDefinitionProcessor.java
  31. 0 31
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValueRegistry.java
  32. 0 38
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/util/BeanRegistrationUtil.java
  33. 0 14
      src/main/java/cn/iocoder/dashboard/framework/apollox/spring/util/SpringInjector.java
  34. 0 4
      src/main/resources/META-INF/spring.factories
  35. 2 3
      src/main/resources/application.yaml

+ 94 - 19
src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java

@@ -1,5 +1,8 @@
 package cn.iocoder.dashboard.framework.apollo.internals;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.config.SysConfigDO;
 import com.ctrip.framework.apollo.Apollo;
 import com.ctrip.framework.apollo.build.ApolloInjector;
 import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
@@ -8,13 +11,20 @@ import com.ctrip.framework.apollo.internals.AbstractConfigRepository;
 import com.ctrip.framework.apollo.internals.ConfigRepository;
 import com.ctrip.framework.apollo.tracer.Tracer;
 import com.ctrip.framework.apollo.util.ConfigUtil;
+import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
 import lombok.extern.slf4j.Slf4j;
-
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
 import java.util.Properties;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
 
 @Slf4j
 public class DBConfigRepository extends AbstractConfigRepository {
@@ -27,15 +37,35 @@ public class DBConfigRepository extends AbstractConfigRepository {
     }
 
     private final ConfigUtil m_configUtil;
-
-    private final AtomicReference<Properties> m_configCache;
+    private PropertiesFactory propertiesFactory;
     private final String m_namespace;
 
+    /**
+     * 配置缓存,使用 Properties 存储
+     */
+    private volatile Properties m_configCache;
+    /**
+     * 缓存配置的最大更新时间,用于后续的增量轮询,判断是否有更新
+     */
+    private volatile Date maxUpdateTime;
+
+    /**
+     * Spring JDBC 操作模板
+     */
+    private final JdbcTemplate jdbcTemplate;
+
     public DBConfigRepository(String namespace) {
         // 初始化变量
         this.m_namespace = namespace;
-        m_configCache = new AtomicReference<>();
-        m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
+        this.propertiesFactory = ApolloInjector.getInstance(PropertiesFactory.class);
+        this.m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
+        // TODO 优化到配置
+        String url = "jdbc:mysql://127.0.1:33061/ruoyi-vue-pro?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT";
+        String username = "root";
+        String password = "123456";
+//        DataSource dataSource = DataSourceBuilder.create().url(url).username(username).password(password).build();
+        DataSource dataSource = new DriverManagerDataSource(url, username, password);
+        this.jdbcTemplate = new JdbcTemplate(dataSource);
 
         // 初始化加载
         this.trySync();
@@ -43,27 +73,32 @@ public class DBConfigRepository extends AbstractConfigRepository {
         this.schedulePeriodicRefresh();
     }
 
-    private AtomicInteger index = new AtomicInteger();
-
     @Override
     protected void sync() {
-        System.out.println("我同步啦");
-
-        index.incrementAndGet();
-        Properties properties = new Properties();
-        properties.setProperty("demo.test", String.valueOf(index.get()));
-        m_configCache.set(properties);
-        super.fireRepositoryChange(m_namespace, properties);
+        // 第一步,尝试获取配置
+        List<SysConfigDO> configs = this.loadConfigIfUpdate(this.maxUpdateTime);
+        if (CollUtil.isEmpty(configs)) { // 如果没有更新,则返回
+            return;
+        }
+        log.info("[sync][同步到新配置,配置数量为:{}]", configs.size());
+
+        // 第二步,构建新的 Properties
+        Properties newProperties = this.buildProperties(configs);
+        this.m_configCache = newProperties;
+        // 第三步,获取最大的配置时间
+        this.maxUpdateTime = configs.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime();
+        // 第四部,触发配置刷新!重要!!!!
+        super.fireRepositoryChange(m_namespace, newProperties);
     }
 
     @Override
     public Properties getConfig() {
         // 兜底,避免可能存在配置为 null 的情况
-        if (m_configCache.get() == null) {
+        if (m_configCache == null) {
             this.trySync();
         }
         // 返回配置
-        return m_configCache.get();
+        return m_configCache;
     }
 
     @Override
@@ -76,6 +111,15 @@ public class DBConfigRepository extends AbstractConfigRepository {
         return ConfigSourceType.REMOTE;
     }
 
+    private Properties buildProperties(List<SysConfigDO> configs) {
+        Properties properties = propertiesFactory.getPropertiesInstance();
+        configs.stream().filter(config -> 0 == config.getDeleted()) // 过滤掉被删除的配置
+                .forEach(config -> properties.put(config.getKey(), config.getValue()));
+        return properties;
+    }
+
+    // ========== 定时器相关操作 ==========
+
     private void schedulePeriodicRefresh() {
         log.debug("Schedule periodic refresh with interval: {} {}",
                 m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit());
@@ -83,7 +127,7 @@ public class DBConfigRepository extends AbstractConfigRepository {
             Tracer.logEvent("Apollo.ConfigService", String.format("periodicRefresh: %s", m_namespace));
             log.debug("refresh config for namespace: {}", m_namespace);
 
-            // 执行同步
+            // 执行同步. 内部已经 try catch 掉异常,无需在处理
             trySync();
 
             Tracer.logEvent("Apollo.Client.Version", Apollo.VERSION);
@@ -92,4 +136,35 @@ public class DBConfigRepository extends AbstractConfigRepository {
 //                TimeUnit.SECONDS);
     }
 
+    // ========== 数据库相关操作 ==========
+
+    /**
+     * 如果配置发生变化,从数据库中获取最新的全量配置。
+     * 如果未发生变化,则返回空
+     *
+     * @param maxUpdateTime 当前配置的最大更新时间
+     * @return 配置列表
+     */
+    private List<SysConfigDO> loadConfigIfUpdate(Date maxUpdateTime) {
+        // 第一步,判断是否要更新。
+        boolean isUpdate = maxUpdateTime == null; // 如果更新时间为空,说明 DB 一定有新数据
+        if (!isUpdate) {
+            isUpdate = this.existsNewConfig(maxUpdateTime); // 判断数据库中是否有更新的配置
+        }
+        if (!isUpdate) {
+            return null;
+        }
+        // 第二步,如果有更新,则从数据库加载所有配置
+        return this.getSysConfigList();
+    }
+
+    private boolean existsNewConfig(Date maxUpdateTime) {
+         return jdbcTemplate.query("SELECT id FROM sys_config WHERE update_time > ? LIMIT 1",
+                 ResultSet::next, maxUpdateTime);
+    }
+
+    private List<SysConfigDO> getSysConfigList() {
+        return jdbcTemplate.query("SELECT `key`, `value`, update_time, deleted FROM sys_config", new BeanPropertyRowMapper<>(SysConfigDO.class));
+    }
+
 }

+ 0 - 35
src/main/java/cn/iocoder/dashboard/framework/apollox/Config.java

@@ -1,35 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox;
-
-import java.util.Set;
-
-/**
- * 配置接口
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public interface Config {
-
-    /**
-     * Return the property value with the given key, or {@code defaultValue} if the key doesn't exist.
-     *
-     * @param key          the property name
-     * @param defaultValue the default value when key is not found or any error occurred
-     * @return the property value
-     */
-    String getProperty(String key, String defaultValue);
-
-    /**
-     * Return a set of the property names
-     *
-     * @return the property names
-     */
-    Set<String> getPropertyNames();
-
-    /**
-     * Add change listener to this config instance.
-     *
-     * @param listener the config change listener
-     */
-    void addChangeListener(ConfigChangeListener listener);
-
-}

+ 0 - 19
src/main/java/cn/iocoder/dashboard/framework/apollox/ConfigChangeListener.java

@@ -1,19 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox;
-
-import cn.iocoder.dashboard.framework.apollox.model.ConfigChangeEvent;
-
-/**
- * {@link Config} 变化监听器
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public interface ConfigChangeListener {
-
-    /**
-     * Invoked when there is any config change for the namespace.
-     *
-     * @param changeEvent the event for this change
-     */
-    void onChange(ConfigChangeEvent changeEvent);
-
-}

+ 0 - 11
src/main/java/cn/iocoder/dashboard/framework/apollox/ConfigService.java

@@ -1,11 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox;
-
-import cn.hutool.core.lang.Singleton;
-
-public class ConfigService {
-
-    public static Config getConfig(String namespace) {
-        return Singleton.get(DefaultConfig.class);
-    }
-
-}

+ 0 - 23
src/main/java/cn/iocoder/dashboard/framework/apollox/DefaultConfig.java

@@ -1,23 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox;
-
-import java.util.Collections;
-import java.util.Set;
-
-public class DefaultConfig implements Config {
-
-    @Override
-    public String getProperty(String key, String defaultValue) {
-        return null;
-    }
-
-    @Override
-    public Set<String> getPropertyNames() {
-        return Collections.emptySet(); // TODO 等下实现
-    }
-
-    @Override
-    public void addChangeListener(ConfigChangeListener listener) {
-
-    }
-
-}

+ 0 - 14
src/main/java/cn/iocoder/dashboard/framework/apollox/enums/PropertyChangeType.java

@@ -1,14 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.enums;
-
-/**
- * 属性变化类型枚举
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public enum PropertyChangeType {
-
-    ADDED, // 添加
-    MODIFIED, // 修改
-    DELETED // 删除
-
-}

+ 0 - 79
src/main/java/cn/iocoder/dashboard/framework/apollox/internals/AbstractConfigRepository.java

@@ -1,79 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.internals;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * 配置 Repository 抽象类
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public abstract class AbstractConfigRepository implements ConfigRepository {
-
-    private static final Logger logger = LoggerFactory.getLogger(AbstractConfigRepository.class);
-
-    /**
-     * RepositoryChangeListener 数组
-     */
-    private List<RepositoryChangeListener> m_listeners = new CopyOnWriteArrayList<>();
-
-    /**
-     * 尝试同步
-     *
-     * @return 是否同步成功
-     */
-    protected boolean trySync() {
-        try {
-            // 同步
-            sync();
-            // 返回同步成功
-            return true;
-        } catch (Throwable ex) {
-//            Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
-            logger.warn("Sync config failed, will retry. Repository {}", getClass(), ex);
-        }
-        // 返回同步失败
-        return false;
-    }
-
-    /**
-     * 同步配置
-     */
-    protected abstract void sync();
-
-    @Override
-    public void addChangeListener(RepositoryChangeListener listener) {
-        if (!m_listeners.contains(listener)) {
-            m_listeners.add(listener);
-        }
-    }
-
-    @Override
-    public void removeChangeListener(RepositoryChangeListener listener) {
-        m_listeners.remove(listener);
-    }
-
-    /**
-     * 触发监听器们
-     *
-     * @param namespace     Namespace 名字
-     * @param newProperties 配置
-     */
-    protected void fireRepositoryChange(String namespace, Properties newProperties) {
-        // 循环 RepositoryChangeListener 数组
-        for (RepositoryChangeListener listener : m_listeners) {
-            try {
-                // 触发监听器
-                listener.onRepositoryChange(namespace, newProperties);
-            } catch (Throwable ex) {
-//                Tracer.logError(ex);
-                logger.error("Failed to invoke repository change listener {}", listener.getClass(), ex);
-            }
-        }
-    }
-
-}

+ 0 - 35
src/main/java/cn/iocoder/dashboard/framework/apollox/internals/ConfigRepository.java

@@ -1,35 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.internals;
-
-import java.util.Properties;
-
-/**
- * 配置 Repository 接口
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public interface ConfigRepository {
-
-    /**
-     * Get the config from this repository.
-     * <p>
-     * 获得配置,以 Properties 对象返回
-     *
-     * @return config
-     */
-    Properties getConfig();
-
-    /**
-     * Add change listener.
-     *
-     * @param listener the listener to observe the changes
-     */
-    void addChangeListener(RepositoryChangeListener listener);
-
-    /**
-     * Remove change listener.
-     *
-     * @param listener the listener to remove
-     */
-    void removeChangeListener(RepositoryChangeListener listener);
-
-}

+ 0 - 345
src/main/java/cn/iocoder/dashboard/framework/apollox/internals/RemoteConfigRepository.java

@@ -1,345 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.internals;
-
-import com.google.common.base.Joiner;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * RemoteConfig Repository
- * <p>
- * 远程配置 Repository ,实现从 Config Service 拉取配置,并缓存在内存中。并且,定时 + 实时刷新缓存。
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public class RemoteConfigRepository extends AbstractConfigRepository {
-
-    private static final Logger logger = LoggerFactory.getLogger(RemoteConfigRepository.class);
-    private static final Joiner STRING_JOINER = Joiner.on(ConfigConsts.CLUSTER_NAMESPACE_SEPARATOR);
-    private static final Joiner.MapJoiner MAP_JOINER = Joiner.on("&").withKeyValueSeparator("=");
-
-    private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
-    private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
-
-    /**
-     * 远程配置长轮询服务
-     */
-    private RemoteConfigLongPollService remoteConfigLongPollService;
-    /**
-     * 指向 ApolloConfig 的 AtomicReference ,缓存配置
-     */
-    private volatile AtomicReference<ApolloConfig> m_configCache;
-    /**
-     * Namespace 名字
-     */
-    private final String m_namespace;
-    /**
-     * ScheduledExecutorService 对象
-     */
-    private final static ScheduledExecutorService m_executorService;
-    /**
-     * 指向 ServiceDTO( Config Service 信息) 的 AtomicReference
-     */
-    private AtomicReference<ServiceDTO> m_longPollServiceDto;
-    /**
-     * 指向 ApolloNotificationMessages 的 AtomicReference
-     */
-    private AtomicReference<ApolloNotificationMessages> m_remoteMessages;
-    /**
-     * 加载配置的 RateLimiter
-     */
-    private RateLimiter m_loadConfigRateLimiter;
-    /**
-     * 是否强制拉取缓存的标记
-     * <p>
-     * 若为 true ,则多一轮从 Config Service 拉取配置
-     * 为 true 的原因,RemoteConfigRepository 知道 Config Service 有配置刷新
-     */
-    private AtomicBoolean m_configNeedForceRefresh;
-    /**
-     * 失败定时重试策略,使用 {@link ExponentialSchedulePolicy}
-     */
-    private SchedulePolicy m_loadConfigFailSchedulePolicy;
-    private Gson gson;
-    private ConfigUtil m_configUtil;
-    private HttpUtil m_httpUtil;
-    private ConfigServiceLocator m_serviceLocator;
-
-    static {
-        // 单线程池
-        m_executorService = Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("RemoteConfigRepository", true));
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param namespace the namespace
-     */
-    public RemoteConfigRepository(String namespace) {
-        m_namespace = namespace;
-        m_configCache = new AtomicReference<>();
-        m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
-        m_httpUtil = ApolloInjector.getInstance(HttpUtil.class);
-        m_serviceLocator = ApolloInjector.getInstance(ConfigServiceLocator.class);
-        remoteConfigLongPollService = ApolloInjector.getInstance(RemoteConfigLongPollService.class);
-        m_longPollServiceDto = new AtomicReference<>();
-        m_remoteMessages = new AtomicReference<>();
-        m_loadConfigRateLimiter = RateLimiter.create(m_configUtil.getLoadConfigQPS());
-        m_configNeedForceRefresh = new AtomicBoolean(true);
-        m_loadConfigFailSchedulePolicy = new ExponentialSchedulePolicy(m_configUtil.getOnErrorRetryInterval(), m_configUtil.getOnErrorRetryInterval() * 8);
-        gson = new Gson();
-        // 尝试同步配置
-        super.trySync();
-        // 初始化定时刷新配置的任务
-        this.schedulePeriodicRefresh();
-        // 注册自己到 RemoteConfigLongPollService 中,实现配置更新的实时通知
-        this.scheduleLongPollingRefresh();
-    }
-
-    @Override
-    public Properties getConfig() {
-        // 如果缓存为空,强制从 Config Service 拉取配置
-        if (m_configCache.get() == null) {
-            this.sync();
-        }
-        // 转换成 Properties 对象,并返回
-        return transformApolloConfigToProperties(m_configCache.get());
-    }
-
-    @Override
-    public void setUpstreamRepository(ConfigRepository upstreamConfigRepository) {
-        // remote config doesn't need upstream
-    }
-
-    private void schedulePeriodicRefresh() {
-        logger.debug("Schedule periodic refresh with interval: {} {}", m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit());
-        // 创建定时任务,定时刷新配置
-        m_executorService.scheduleAtFixedRate(new Runnable() {
-            @Override
-            public void run() {
-                // 【TODO 6001】Tracer 日志
-                Tracer.logEvent("Apollo.ConfigService", String.format("periodicRefresh: %s", m_namespace));
-                logger.debug("refresh config for namespace: {}", m_namespace);
-                // 尝试同步配置
-                trySync();
-                // 【TODO 6001】Tracer 日志
-                Tracer.logEvent("Apollo.Client.Version", Apollo.VERSION);
-            }
-        }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit());
-    }
-
-    @Override
-    protected synchronized void sync() {
-        // 【TODO 6001】Tracer 日志
-        Transaction transaction = Tracer.newTransaction("Apollo.ConfigService", "syncRemoteConfig");
-        try {
-            // 获得缓存的 ApolloConfig 对象
-            ApolloConfig previous = m_configCache.get();
-            // 从 Config Service 加载 ApolloConfig 对象
-            ApolloConfig current = loadApolloConfig();
-
-            // reference equals means HTTP 304
-            // 若不相等,说明更新了,设置到缓存中
-            if (previous != current) {
-                logger.debug("Remote Config refreshed!");
-                // 设置到缓存
-                m_configCache.set(current);
-                // 发布 Repository 的配置发生变化,触发对应的监听器们
-                super.fireRepositoryChange(m_namespace, this.getConfig());
-            }
-            // 【TODO 6001】Tracer 日志
-            if (current != null) {
-                Tracer.logEvent(String.format("Apollo.Client.Configs.%s", current.getNamespaceName()), current.getReleaseKey());
-            }
-            // 【TODO 6001】Tracer 日志
-            transaction.setStatus(Transaction.SUCCESS);
-        } catch (Throwable ex) {
-            // 【TODO 6001】Tracer 日志
-            transaction.setStatus(ex);
-            throw ex;
-        } finally {
-            // 【TODO 6001】Tracer 日志
-            transaction.complete();
-        }
-    }
-
-    private Properties transformApolloConfigToProperties(ApolloConfig apolloConfig) {
-        Properties result = new Properties();
-        result.putAll(apolloConfig.getConfigurations());
-        return result;
-    }
-
-    private ApolloConfig loadApolloConfig() {
-        // 限流
-        if (!m_loadConfigRateLimiter.tryAcquire(5, TimeUnit.SECONDS)) {
-            // wait at most 5 seconds
-            try {
-                TimeUnit.SECONDS.sleep(5);
-            } catch (InterruptedException e) {
-            }
-        }
-        // 获得 appId cluster dataCenter 配置信息
-        String appId = m_configUtil.getAppId();
-        String cluster = m_configUtil.getCluster();
-        String dataCenter = m_configUtil.getDataCenter();
-        Tracer.logEvent("Apollo.Client.ConfigMeta", STRING_JOINER.join(appId, cluster, m_namespace));
-        // 计算重试次数
-        int maxRetries = m_configNeedForceRefresh.get() ? 2 : 1;
-        long onErrorSleepTime = 0; // 0 means no sleep
-        Throwable exception = null;
-        // 获得所有的 Config Service 的地址
-        List<ServiceDTO> configServices = getConfigServices();
-        String url = null;
-        // 循环读取配置重试次数直到成功。每一次,都会循环所有的 ServiceDTO 数组。
-        for (int i = 0; i < maxRetries; i++) {
-            // 随机所有的 Config Service 的地址
-            List<ServiceDTO> randomConfigServices = Lists.newLinkedList(configServices);
-            Collections.shuffle(randomConfigServices);
-            // 优先访问通知配置变更的 Config Service 的地址。并且,获取到时,需要置空,避免重复优先访问。
-            // Access the server which notifies the client first
-            if (m_longPollServiceDto.get() != null) {
-                randomConfigServices.add(0, m_longPollServiceDto.getAndSet(null));
-            }
-            // 循环所有的 Config Service 的地址
-            for (ServiceDTO configService : randomConfigServices) {
-                // sleep 等待,下次从 Config Service 拉取配置
-                if (onErrorSleepTime > 0) {
-                    logger.warn("Load config failed, will retry in {} {}. appId: {}, cluster: {}, namespaces: {}", onErrorSleepTime, m_configUtil.getOnErrorRetryIntervalTimeUnit(), appId, cluster, m_namespace);
-                    try {
-                        m_configUtil.getOnErrorRetryIntervalTimeUnit().sleep(onErrorSleepTime);
-                    } catch (InterruptedException e) {
-                        //ignore
-                    }
-                }
-                // 组装查询配置的地址
-                url = assembleQueryConfigUrl(configService.getHomepageUrl(), appId, cluster, m_namespace, dataCenter, m_remoteMessages.get(), m_configCache.get());
-
-                logger.debug("Loading config from {}", url);
-                // 创建 HttpRequest 对象
-                HttpRequest request = new HttpRequest(url);
-
-                // 【TODO 6001】Tracer 日志
-                Transaction transaction = Tracer.newTransaction("Apollo.ConfigService", "queryConfig");
-                transaction.addData("Url", url);
-                try {
-                    // 发起请求,返回 HttpResponse 对象
-                    HttpResponse<ApolloConfig> response = m_httpUtil.doGet(request, ApolloConfig.class);
-                    // 设置 m_configNeedForceRefresh = false
-                    m_configNeedForceRefresh.set(false);
-                    // 标记成功
-                    m_loadConfigFailSchedulePolicy.success();
-
-                    // 【TODO 6001】Tracer 日志
-                    transaction.addData("StatusCode", response.getStatusCode());
-                    transaction.setStatus(Transaction.SUCCESS);
-
-                    // 无新的配置,直接返回缓存的 ApolloConfig 对象
-                    if (response.getStatusCode() == 304) {
-                        logger.debug("Config server responds with 304 HTTP status code.");
-                        return m_configCache.get();
-                    }
-
-                    // 有新的配置,进行返回新的 ApolloConfig 对象
-                    ApolloConfig result = response.getBody();
-                    logger.debug("Loaded config for {}: {}", m_namespace, result);
-                    return result;
-                } catch (ApolloConfigStatusCodeException ex) {
-                    ApolloConfigStatusCodeException statusCodeException = ex;
-                    // 若返回的状态码是 404 ,说明查询配置的 Config Service 不存在该 Namespace 。
-                    // config not found
-                    if (ex.getStatusCode() == 404) {
-                        String message = String.format("Could not find config for namespace - appId: %s, cluster: %s, namespace: %s, " +
-                                "please check whether the configs are released in Apollo!", appId, cluster, m_namespace);
-                        statusCodeException = new ApolloConfigStatusCodeException(ex.getStatusCode(), message);
-                    }
-                    // 【TODO 6001】Tracer 日志
-                    Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(statusCodeException));
-                    transaction.setStatus(statusCodeException);
-                    // 设置最终的异常
-                    exception = statusCodeException;
-                } catch (Throwable ex) {
-                    // 【TODO 6001】Tracer 日志
-                    Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
-                    transaction.setStatus(ex);
-                    // 设置最终的异常
-                    exception = ex;
-                } finally {
-                    // 【TODO 6001】Tracer 日志
-                    transaction.complete();
-                }
-                // 计算延迟时间
-                // if force refresh, do normal sleep, if normal config load, do exponential sleep
-                onErrorSleepTime = m_configNeedForceRefresh.get() ? m_configUtil.getOnErrorRetryInterval() : m_loadConfigFailSchedulePolicy.fail();
-            }
-
-        }
-        // 若查询配置失败,抛出 ApolloConfigException 异常
-        String message = String.format("Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s, url: %s", appId, cluster, m_namespace, url);
-        throw new ApolloConfigException(message, exception);
-    }
-
-    // 组装查询配置的地址
-    String assembleQueryConfigUrl(String uri, String appId, String cluster, String namespace,
-                                  String dataCenter, ApolloNotificationMessages remoteMessages, ApolloConfig previousConfig) {
-        String path = "configs/%s/%s/%s"; // /configs/{appId}/{clusterName}/{namespace:.+}
-        List<String> pathParams = Lists.newArrayList(pathEscaper.escape(appId), pathEscaper.escape(cluster), pathEscaper.escape(namespace));
-        Map<String, String> queryParams = Maps.newHashMap();
-        // releaseKey
-        if (previousConfig != null) {
-            queryParams.put("releaseKey", queryParamEscaper.escape(previousConfig.getReleaseKey()));
-        }
-        // dataCenter
-        if (!Strings.isNullOrEmpty(dataCenter)) {
-            queryParams.put("dataCenter", queryParamEscaper.escape(dataCenter));
-        }
-        // ip
-        String localIp = m_configUtil.getLocalIp();
-        if (!Strings.isNullOrEmpty(localIp)) {
-            queryParams.put("ip", queryParamEscaper.escape(localIp));
-        }
-        // messages
-        if (remoteMessages != null) {
-            queryParams.put("messages", queryParamEscaper.escape(gson.toJson(remoteMessages)));
-        }
-        // 格式化 URL
-        String pathExpanded = String.format(path, pathParams.toArray());
-        // 拼接 Query String
-        if (!queryParams.isEmpty()) {
-            pathExpanded += "?" + MAP_JOINER.join(queryParams);
-        }
-        // 拼接最终的请求 URL
-        if (!uri.endsWith("/")) {
-            uri += "/";
-        }
-        return uri + pathExpanded;
-    }
-
-    /**
-     * 注册自己到 RemoteConfigLongPollService 中,实现配置更新的实时通知
-     */
-    private void scheduleLongPollingRefresh() {
-        remoteConfigLongPollService.submit(m_namespace, this);
-    }
-
-    /**
-     * 当长轮询到配置更新时,发起同步配置的任务
-     *
-     * @param longPollNotifiedServiceDto ServiceDTO 对象
-     * @param remoteMessages             ApolloNotificationMessages 对象
-     */
-    public void onLongPollNotified(ServiceDTO longPollNotifiedServiceDto, ApolloNotificationMessages remoteMessages) {
-        // 提交同步任务
-        m_executorService.submit(new Runnable() {
-
-            @Override
-            public void run() {
-                // 设置 m_configNeedForceRefresh 为 true
-                m_configNeedForceRefresh.set(true);
-                // 尝试同步配置
-                trySync();
-            }
-
-        });
-    }
-
-
-}

+ 0 - 18
src/main/java/cn/iocoder/dashboard/framework/apollox/internals/RepositoryChangeListener.java

@@ -1,18 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.internals;
-
-import java.util.Properties;
-
-/**
- * @author Jason Song(song_s@ctrip.com)
- */
-public interface RepositoryChangeListener {
-
-    /**
-     * Invoked when config repository changes.
-     *
-     * @param namespace     the namespace of this repository change
-     * @param newProperties the properties after change
-     */
-    void onRepositoryChange(String namespace, Properties newProperties);
-
-}

+ 0 - 35
src/main/java/cn/iocoder/dashboard/framework/apollox/model/ConfigChange.java

@@ -1,35 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.model;
-
-
-import cn.iocoder.dashboard.framework.apollox.enums.PropertyChangeType;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-/**
- * Holds the information for a config change.
- * 配置每个属性变化的信息
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-@Data
-@AllArgsConstructor
-public class ConfigChange {
-
-    /**
-     * 属性名
-     */
-    private final String propertyName;
-    /**
-     * 老值
-     */
-    private String oldValue;
-    /**
-     * 新值
-     */
-    private String newValue;
-    /**
-     * 变化类型
-     */
-    private PropertyChangeType changeType;
-
-}

+ 0 - 53
src/main/java/cn/iocoder/dashboard/framework/apollox/model/ConfigChangeEvent.java

@@ -1,53 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.model;
-
-import lombok.AllArgsConstructor;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A change event when a namespace's config is changed.
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-@AllArgsConstructor
-public class ConfigChangeEvent {
-
-    /**
-     * 变化属性的集合
-     *
-     * KEY:属性名
-     * VALUE:配置变化
-     */
-    private final Map<String, ConfigChange> m_changes;
-
-    /**
-     * Get the keys changed.
-     *
-     * @return the list of the keys
-     */
-    public Set<String> changedKeys() {
-        return m_changes.keySet();
-    }
-
-    /**
-     * Get a specific change instance for the key specified.
-     *
-     * @param key the changed key
-     * @return the change instance
-     */
-    public ConfigChange getChange(String key) {
-        return m_changes.get(key);
-    }
-
-    /**
-     * Check whether the specified key is changed
-     *
-     * @param key the key
-     * @return true if the key is changed, false otherwise.
-     */
-    public boolean isChanged(String key) {
-        return m_changes.containsKey(key);
-    }
-
-}

+ 0 - 16
src/main/java/cn/iocoder/dashboard/framework/apollox/package-info.java

@@ -1,16 +0,0 @@
-/**
- * 配置中心客户端,基于 Apollo Client 实现,所以叫 ApolloX
- *
- * 差别在于,我们使用 {@link cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.config.SysConfigDO} 表作为配置源。
- * 当然,功能肯定也会相对少些,满足最小化诉求。
- *
- * 1. 项目初始化时,可以使用 SysConfigDO 表的配置
- * 2. 使用 Spring @Value 可以注入属性
- * 3. SysConfigDO 表的配置修改时,注入到 @Value 的属性可以刷新
- *
- * 另外,整个包结构会参考 Apollo 为主,方便维护与理解
- *
- * 注意,目前有两个特性是不支持的
- * 1. 自定义配置变化的监听器
- */
-package cn.iocoder.dashboard.framework.apollox;

+ 0 - 61
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloAnnotationProcessor.java

@@ -1,61 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.annotation;
-
-import cn.hutool.core.lang.Singleton;
-import cn.iocoder.dashboard.framework.apollox.Config;
-import cn.iocoder.dashboard.framework.apollox.ConfigChangeListener;
-import cn.iocoder.dashboard.framework.apollox.DefaultConfig;
-import cn.iocoder.dashboard.framework.apollox.model.ConfigChangeEvent;
-import com.google.common.base.Preconditions;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.util.ReflectionUtils;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-/**
- * Apollo Annotation Processor for Spring Application
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public class ApolloAnnotationProcessor extends ApolloProcessor {
-
-    @Override
-    protected void processField(Object bean, String beanName, Field field) {
-        ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class);
-        if (annotation == null) {
-            return;
-        }
-
-        Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()), "Invalid type: %s for field: %s, should be Config", field.getType(), field);
-
-        // 创建 Config 对象
-        Config config = Singleton.get(DefaultConfig.class);
-
-        // 设置 Config 对象,到对应的 Field
-        ReflectionUtils.makeAccessible(field);
-        ReflectionUtils.setField(field, bean, config);
-    }
-
-    @Override
-    protected void processMethod(final Object bean, String beanName, final Method method) {
-        ApolloConfigChangeListener annotation = AnnotationUtils.findAnnotation(method, ApolloConfigChangeListener.class);
-        if (annotation == null) {
-            return;
-        }
-        Class<?>[] parameterTypes = method.getParameterTypes();
-        Preconditions.checkArgument(parameterTypes.length == 1, "Invalid number of parameters: %s for method: %s, should be 1", parameterTypes.length, method);
-        Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]), "Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", parameterTypes[0], method);
-
-        // 创建 ConfigChangeListener 监听器。该监听器会调用被注解的方法。
-        ReflectionUtils.makeAccessible(method);
-        ConfigChangeListener configChangeListener = changeEvent -> {
-            // 反射调用
-            ReflectionUtils.invokeMethod(method, bean, changeEvent);
-        };
-
-        // 向指定 Namespace 的 Config 对象们,注册该监听器
-        Config config = Singleton.get(DefaultConfig.class);
-        config.addChangeListener(configChangeListener);
-    }
-
-}

+ 0 - 22
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloConfig.java

@@ -1,22 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.annotation;
-
-import java.lang.annotation.*;
-
-/**
- * Use this annotation to inject Apollo Config Instance.
- *
- * <p>Usage example:</p>
- * <pre class="code">
- * //Inject the config for "someNamespace"
- * &#064;ApolloConfig("someNamespace")
- * private Config config;
- * </pre>
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-@Documented
-public @interface ApolloConfig {
-
-}

+ 0 - 15
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloConfigChangeListener.java

@@ -1,15 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.annotation;
-
-import java.lang.annotation.*;
-
-/**
- * Use this annotation to register Apollo ConfigChangeListener.
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-@Documented
-public @interface ApolloConfigChangeListener {
-
-}

+ 0 - 68
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/ApolloProcessor.java

@@ -1,68 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.annotation;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanPostProcessor;
-import org.springframework.core.Ordered;
-import org.springframework.core.PriorityOrdered;
-import org.springframework.util.ReflectionUtils;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Apollo 处理器抽象类,封装了在 Spring Bean 初始化之前,处理属性和方法。
- *
- * Create by zhangzheng on 2018/2/6
- */
-public abstract class ApolloProcessor implements BeanPostProcessor, PriorityOrdered {
-
-    @Override
-    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-        Class<?> clazz = bean.getClass();
-        // 处理所有 Field
-        for (Field field : findAllField(clazz)) {
-            processField(bean, beanName, field);
-        }
-        // 处理所有的 Method
-        for (Method method : findAllMethod(clazz)) {
-            processMethod(bean, beanName, method);
-        }
-        return bean;
-    }
-
-    @Override
-    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
-        return bean;
-    }
-
-    /**
-     * subclass should implement this method to process field
-     */
-    protected abstract void processField(Object bean, String beanName, Field field);
-
-    /**
-     * subclass should implement this method to process method
-     */
-    protected abstract void processMethod(Object bean, String beanName, Method method);
-
-    @Override
-    public int getOrder() {
-        // make it as late as possible
-        return Ordered.LOWEST_PRECEDENCE; // 最高优先级
-    }
-
-    private List<Field> findAllField(Class<?> clazz) {
-        final List<Field> res = new LinkedList<>();
-        ReflectionUtils.doWithFields(clazz, res::add);
-        return res;
-    }
-
-    private List<Method> findAllMethod(Class<?> clazz) {
-        final List<Method> res = new LinkedList<>();
-        ReflectionUtils.doWithMethods(clazz, res::add);
-        return res;
-    }
-
-}

+ 0 - 141
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/annotation/SpringValueProcessor.java

@@ -1,141 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.annotation;
-
-import cn.hutool.core.lang.Singleton;
-import cn.iocoder.dashboard.framework.apollox.spring.property.*;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.Multimap;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.context.annotation.Bean;
-
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * Spring value processor of field or method which has @Value and xml config placeholders.
- *
- * Spring Value 处理器,处理:
- *
- * 1. 带有 `@Value` 注解的 Field 和 Method
- * 2. XML 配置的 Bean 的 PlaceHolder 们
- *
- * 每个 Field、Method、XML PlaceHolder 被处理成一个 SpringValue 对象,添加到 SpringValueRegistry 中。
- *
- * 目的还是,为了 PlaceHolder 的自动更新机制。
- *
- * @author github.com/zhegexiaohuozi  seimimaster@gmail.com
- * @since 2017/12/20.
- */
-@Slf4j
-public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor {
-
-    /**
-     * SpringValueDefinition 集合
-     *
-     * KEY:beanName
-     * VALUE:SpringValueDefinition 集合
-     */
-    private static Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions = LinkedListMultimap.create();
-
-    private final PlaceholderHelper placeholderHelper = Singleton.get(PlaceholderHelper.class);
-    private final SpringValueRegistry springValueRegistry = Singleton.get(SpringValueRegistry.class);
-
-    @Override
-    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-        beanName2SpringValueDefinitions = SpringValueDefinitionProcessor.getBeanName2SpringValueDefinitions();
-    }
-
-    @Override
-    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-        // 处理 Field 和 Method
-        super.postProcessBeforeInitialization(bean, beanName);
-        // 处理 XML 配置的 Bean 的 PlaceHolder 们
-        processBeanPropertyValues(bean, beanName);
-        return bean;
-    }
-
-    @Override
-    protected void processField(Object bean, String beanName, Field field) {
-        // register @Value on field
-        Value value = field.getAnnotation(Value.class);
-        if (value == null) {
-            return;
-        }
-        // 提取 `keys` 属性们。
-        Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
-        if (keys.isEmpty()) {
-            return;
-        }
-        // 循环 `keys` ,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
-        for (String key : keys) {
-            SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);
-            springValueRegistry.register(key, springValue);
-            log.debug("Monitoring {}", springValue);
-        }
-    }
-
-    @Override
-    protected void processMethod(Object bean, String beanName, Method method) {
-        // register @Value on method
-        Value value = method.getAnnotation(Value.class);
-        if (value == null) {
-            return;
-        }
-        // 忽略 @Bean 注解的方法
-        // skip Configuration bean methods
-        if (method.getAnnotation(Bean.class) != null) {
-            return;
-        }
-        // 忽略非 setting 方法
-        if (method.getParameterTypes().length != 1) {
-            log.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters", bean.getClass().getName(), method.getName(), method.getParameterTypes().length);
-            return;
-        }
-        // 提取 `keys` 属性们。
-        Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
-        if (keys.isEmpty()) {
-            return;
-        }
-        // 循环 `keys` ,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
-        for (String key : keys) {
-            SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
-            springValueRegistry.register(key, springValue);
-            log.info("Monitoring {}", springValue);
-        }
-    }
-
-    private void processBeanPropertyValues(Object bean, String beanName) {
-        // 获得 SpringValueDefinition 数组
-        Collection<SpringValueDefinition> propertySpringValues = beanName2SpringValueDefinitions.get(beanName);
-        if (propertySpringValues == null || propertySpringValues.isEmpty()) {
-            return;
-        }
-        // 循环 SpringValueDefinition 数组,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
-        for (SpringValueDefinition definition : propertySpringValues) {
-            try {
-                PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(bean.getClass(), definition.getPropertyName());
-                Method method = pd.getWriteMethod();
-                if (method == null) {
-                    continue;
-                }
-                SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(), bean, beanName, method, false);
-                springValueRegistry.register(definition.getKey(), springValue);
-                log.debug("Monitoring {}", springValue);
-            } catch (Throwable ex) {
-                log.error("Failed to enable auto update feature for {}.{}", bean.getClass(), definition.getPropertyName());
-            }
-        }
-
-        // clear
-        // 移除 Bean 对应的 SpringValueDefinition 数组
-        beanName2SpringValueDefinitions.removeAll(beanName);
-    }
-
-}

+ 0 - 57
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/boot/ApolloApplicationContextInitializer.java

@@ -1,57 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.boot;
-
-
-import cn.iocoder.dashboard.framework.apollox.Config;
-import cn.iocoder.dashboard.framework.apollox.ConfigService;
-import cn.iocoder.dashboard.framework.apollox.spring.config.ConfigPropertySourceFactory;
-import cn.iocoder.dashboard.framework.apollox.spring.config.PropertySourcesConstants;
-import cn.iocoder.dashboard.framework.apollox.spring.util.SpringInjector;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.ApplicationContextInitializer;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.core.env.CompositePropertySource;
-import org.springframework.core.env.ConfigurableEnvironment;
-
-import java.util.Collections;
-import java.util.List;
-
-import static cn.iocoder.dashboard.framework.apollox.spring.config.PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME;
-
-@Slf4j
-public class ApolloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
-
-    private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector.getInstance(ConfigPropertySourceFactory.class);
-
-    @Override
-    public void initialize(ConfigurableApplicationContext context) {
-        ConfigurableEnvironment environment = context.getEnvironment();
-        // 忽略,若已经有 APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME 的 PropertySource
-        if (environment.getPropertySources().contains(APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
-            // already initialized
-            return;
-        }
-
-        // 忽略,若已经有 APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME 的 PropertySource
-        if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
-            // already initialized
-            return;
-        }
-
-        // 获得 "apollo.bootstrap.namespaces" 配置项
-        List<String> namespaceList = Collections.singletonList("default");
-
-        // 按照优先级,顺序遍历 Namespace
-        CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
-        for (String namespace : namespaceList) {
-            // 创建 Apollo Config 对象
-            Config config = ConfigService.getConfig(namespace);
-            // 创建 Namespace 对应的 ConfigPropertySource 对象
-            // 添加到 `composite` 中。
-            composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
-        }
-
-        // 添加到 `environment` 中,且优先级最高
-        environment.getPropertySources().addFirst(composite);
-    }
-
-}

+ 0 - 18
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/boot/ApolloAutoConfiguration.java

@@ -1,18 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.boot;
-
-import cn.iocoder.dashboard.framework.apollox.spring.config.ConfigPropertySourcesProcessor;
-import cn.iocoder.dashboard.framework.apollox.spring.property.PropertySourcesProcessor;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-@ConditionalOnMissingBean(PropertySourcesProcessor.class) // 缺失 PropertySourcesProcessor 时
-public class ApolloAutoConfiguration {
-
-    @Bean
-    public ConfigPropertySourcesProcessor configPropertySourcesProcessor() {
-        return new ConfigPropertySourcesProcessor(); // 注入 ConfigPropertySourcesProcessor bean 对象
-    }
-
-}

+ 0 - 49
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/ConfigPropertySource.java

@@ -1,49 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.config;
-
-import cn.iocoder.dashboard.framework.apollox.Config;
-import cn.iocoder.dashboard.framework.apollox.ConfigChangeListener;
-import org.springframework.core.env.EnumerablePropertySource;
-
-import java.util.Set;
-
-/**
- * Property source wrapper for Config
- *
- * 基于 {@link Config} 的 PropertySource 实现类
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public class ConfigPropertySource extends EnumerablePropertySource<Config> {
-
-    private static final String[] EMPTY_ARRAY = new String[0];
-
-    ConfigPropertySource(String name, Config source) { // 此处的 Apollo Config 作为 `source`
-        super(name, source);
-    }
-
-    @Override
-    public String[] getPropertyNames() {
-        // 从 Config 中,获得属性名集合
-        Set<String> propertyNames = this.source.getPropertyNames();
-        // 转换成 String 数组,返回
-        if (propertyNames.isEmpty()) {
-            return EMPTY_ARRAY;
-        }
-        return propertyNames.toArray(new String[0]);
-    }
-
-    @Override
-    public Object getProperty(String name) {
-        return this.source.getProperty(name, null);
-    }
-
-    /**
-     * 添加 ConfigChangeListener 到 Config 中
-     *
-     * @param listener 监听器
-     */
-    public void addChangeListener(ConfigChangeListener listener) {
-        this.source.addChangeListener(listener);
-    }
-
-}

+ 0 - 31
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/ConfigPropertySourceFactory.java

@@ -1,31 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.config;
-
-import cn.iocoder.dashboard.framework.apollox.Config;
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-/**
- * {@link ConfigPropertySource} 工厂
- */
-public class ConfigPropertySourceFactory {
-
-    /**
-     * ConfigPropertySource 数组
-     */
-    private final List<ConfigPropertySource> configPropertySources = Lists.newLinkedList();
-
-    // 创建 ConfigPropertySource 对象
-    public ConfigPropertySource getConfigPropertySource(String name, Config source) {
-        // 创建 ConfigPropertySource 对象
-        ConfigPropertySource configPropertySource = new ConfigPropertySource(name, source);
-        // 添加到数组中
-        configPropertySources.add(configPropertySource);
-        return configPropertySource;
-    }
-
-    public List<ConfigPropertySource> getAllConfigPropertySources() {
-        return Lists.newLinkedList(configPropertySources);
-    }
-
-}

+ 0 - 47
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/ConfigPropertySourcesProcessor.java

@@ -1,47 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.config;
-
-import cn.iocoder.dashboard.framework.apollox.spring.annotation.ApolloAnnotationProcessor;
-import cn.iocoder.dashboard.framework.apollox.spring.annotation.SpringValueProcessor;
-import cn.iocoder.dashboard.framework.apollox.spring.property.PropertySourcesProcessor;
-import cn.iocoder.dashboard.framework.apollox.spring.property.SpringValueDefinitionProcessor;
-import cn.iocoder.dashboard.framework.apollox.spring.util.BeanRegistrationUtil;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
-import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
-
-/**
- * Apollo Property Sources processor for Spring XML Based Application
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public class ConfigPropertySourcesProcessor extends PropertySourcesProcessor implements BeanDefinitionRegistryPostProcessor {
-
-    @Override
-    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
-        // 注册 PropertySourcesPlaceholderConfigurer 到 BeanDefinitionRegistry 中,替换 PlaceHolder 为对应的属性值,参考文章 https://leokongwq.github.io/2016/12/28/spring-PropertyPlaceholderConfigurer.html
-        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(), PropertySourcesPlaceholderConfigurer.class);
-        // 注册 ApolloAnnotationProcessor 到 BeanDefinitionRegistry 中,因为 XML 配置的 Bean 对象,也可能存在 @ApolloConfig 和 @ApolloConfigChangeListener 注解。
-        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(), ApolloAnnotationProcessor.class);
-        // 注册 SpringValueProcessor 到 BeanDefinitionRegistry 中,用于 PlaceHolder 自动更新机制
-        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class);
-        // 注册 ApolloJsonValueProcessor 到 BeanDefinitionRegistry 中,因为 XML 配置的 Bean 对象,也可能存在 @ApolloJsonValue 注解。
-//        BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(), ApolloJsonValueProcessor.class); TODO 芋艿:暂时不需要迁移
-
-        // 处理 XML 配置的 Spring PlaceHolder
-        processSpringValueDefinition(registry);
-    }
-
-    /**
-     * For Spring 3.x versions, the BeanDefinitionRegistryPostProcessor would not be
-     * instantiated if it is added in postProcessBeanDefinitionRegistry phase, so we have to manually
-     * call the postProcessBeanDefinitionRegistry method of SpringValueDefinitionProcessor here...
-     */
-    private void processSpringValueDefinition(BeanDefinitionRegistry registry) {
-        // 创建 SpringValueDefinitionProcessor 对象
-        SpringValueDefinitionProcessor springValueDefinitionProcessor = new SpringValueDefinitionProcessor();
-        // 处理 XML 配置的 Spring PlaceHolder
-        springValueDefinitionProcessor.postProcessBeanDefinitionRegistry(registry);
-    }
-
-}

+ 0 - 9
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/config/PropertySourcesConstants.java

@@ -1,9 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.config;
-
-public interface PropertySourcesConstants {
-
-  String APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME = "ApolloBootstrapPropertySources";
-
-    String APOLLO_PROPERTY_SOURCE_NAME = "ApolloPropertySources";
-
-}

+ 0 - 159
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/AutoUpdateConfigChangeListener.java

@@ -1,159 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.property;
-
-import cn.hutool.core.lang.Singleton;
-import cn.iocoder.dashboard.framework.apollox.ConfigChangeListener;
-import cn.iocoder.dashboard.framework.apollox.enums.PropertyChangeType;
-import cn.iocoder.dashboard.framework.apollox.model.ConfigChange;
-import cn.iocoder.dashboard.framework.apollox.model.ConfigChangeEvent;
-import com.alibaba.fastjson.JSON;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.TypeConverter;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.core.env.Environment;
-import org.springframework.util.CollectionUtils;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Type;
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * 自动更新配置监听器
- *
- * Create by zhangzheng on 2018/3/6
- */
-public class AutoUpdateConfigChangeListener implements ConfigChangeListener {
-
-    private static final Logger logger = LoggerFactory.getLogger(AutoUpdateConfigChangeListener.class);
-
-    /**
-     * {@link TypeConverter#convertIfNecessary(Object, Class, Field)} 是否带上 Field 参数,因为 Spring 3.2.0+ 才有该方法
-     */
-    private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter;
-    private final Environment environment;
-    private final ConfigurableBeanFactory beanFactory;
-    /**
-     * TypeConverter 对象,参见 https://blog.csdn.net/rulerp2014/article/details/51100857
-     */
-    private final TypeConverter typeConverter;
-    private final PlaceholderHelper placeholderHelper;
-    private final SpringValueRegistry springValueRegistry;
-
-    public AutoUpdateConfigChangeListener(Environment environment, ConfigurableListableBeanFactory beanFactory) {
-        this.typeConverterHasConvertIfNecessaryWithFieldParameter = testTypeConverterHasConvertIfNecessaryWithFieldParameter();
-        this.beanFactory = beanFactory;
-        this.typeConverter = this.beanFactory.getTypeConverter();
-        this.environment = environment;
-        this.placeholderHelper = Singleton.get(PlaceholderHelper.class);
-        this.springValueRegistry = Singleton.get(SpringValueRegistry.class);
-    }
-
-    @Override
-    public void onChange(ConfigChangeEvent changeEvent) {
-        // 获得更新的 KEY 集合
-        Set<String> keys = changeEvent.changedKeys();
-        if (CollectionUtils.isEmpty(keys)) {
-            return;
-        }
-        // 循环 KEY 集合,更新 StringValue
-        for (String key : keys) {
-            // 忽略,若不在 SpringValueRegistry 中
-            // 1. check whether the changed key is relevant
-            Collection<SpringValue> targetValues = springValueRegistry.get(key);
-            if (targetValues == null || targetValues.isEmpty()) {
-                continue;
-            }
-            // 校验是否需要更新
-            // 2. check whether the value is really changed or not (since spring property sources have hierarchies)
-            if (!shouldTriggerAutoUpdate(changeEvent, key)) {
-                continue;
-            }
-            // 循环,更新 SpringValue
-            // 3. update the value
-            for (SpringValue val : targetValues) {
-                updateSpringValue(val);
-            }
-        }
-    }
-
-    /**
-     * Check whether we should trigger the auto update or not.
-     * <br />
-     * For added or modified keys, we should trigger auto update if the current value in Spring equals to the new value.
-     * <br />
-     * For deleted keys, we will trigger auto update anyway.
-     */
-    private boolean shouldTriggerAutoUpdate(ConfigChangeEvent changeEvent, String changedKey) {
-        ConfigChange configChange = changeEvent.getChange(changedKey);
-        // 若变更类型为删除,需要触发更新
-        if (configChange.getChangeType() == PropertyChangeType.DELETED) {
-            return true;
-        }
-        // 若变更类型为新增或修改,判断 environment 的值是否和最新值相等。
-        // 【高能】!!!
-        return Objects.equals(environment.getProperty(changedKey), configChange.getNewValue());
-    }
-
-    private void updateSpringValue(SpringValue springValue) {
-        try {
-            // 解析值
-            Object value = resolvePropertyValue(springValue);
-            // 更新 StringValue
-            springValue.update(value);
-            logger.info("Auto update apollo changed value successfully, new value: {}, {}", value, springValue);
-        } catch (Throwable ex) {
-            logger.error("Auto update apollo changed value failed, {}", springValue.toString(), ex);
-        }
-    }
-
-    /**
-     * Logic transplanted from DefaultListableBeanFactory
-     *
-     * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, String, Set, TypeConverter)
-     */
-    private Object resolvePropertyValue(SpringValue springValue) {
-        // value will never be null, as @Value and @ApolloJsonValue will not allow that
-        Object value = placeholderHelper.resolvePropertyValue(beanFactory, springValue.getBeanName(), springValue.getPlaceholder());
-        // 如果值数据结构是 JSON 类型,则使用 Gson 解析成对应值的类型
-        if (springValue.isJson()) {
-            value = parseJsonValue((String) value, springValue.getGenericType());
-        } else {
-            // 如果类型为 Field
-            if (springValue.isField()) {
-                // org.springframework.beans.TypeConverter#convertIfNecessary(java.lang.Object, java.lang.Class, java.lang.reflect.Field) is available from Spring 3.2.0+
-                if (typeConverterHasConvertIfNecessaryWithFieldParameter) {
-                    value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getField());
-                } else {
-                    value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType());
-                }
-            // 如果类型为 Method
-            } else {
-                value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getMethodParameter());
-            }
-        }
-
-        return value;
-    }
-
-    private Object parseJsonValue(String json, Type targetType) {
-        try {
-            return JSON.parseObject(json, targetType);
-        } catch (Throwable ex) {
-            logger.error("Parsing json '{}' to type {} failed!", json, targetType, ex);
-            throw ex;
-        }
-    }
-
-    private boolean testTypeConverterHasConvertIfNecessaryWithFieldParameter() {
-        try {
-            TypeConverter.class.getMethod("convertIfNecessary", Object.class, Class.class, Field.class);
-        } catch (Throwable ex) {
-            return false;
-        }
-        return true;
-    }
-
-}

+ 0 - 160
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/PlaceholderHelper.java

@@ -1,160 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.property;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.Sets;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.BeanExpressionContext;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.beans.factory.config.Scope;
-import org.springframework.util.StringUtils;
-
-import java.util.Set;
-import java.util.Stack;
-
-/**
- * Placeholder 工具类
- *
- * Placeholder helper functions.
- */
-public class PlaceholderHelper {
-
-    private static final String PLACEHOLDER_PREFIX = "${";
-    private static final String PLACEHOLDER_SUFFIX = "}";
-    private static final String VALUE_SEPARATOR = ":";
-    private static final String SIMPLE_PLACEHOLDER_PREFIX = "{";
-    private static final String EXPRESSION_PREFIX = "#{";
-    private static final String EXPRESSION_SUFFIX = "}";
-
-    /**
-     * Resolve placeholder property values, e.g.
-     *
-     * "${somePropertyValue}" -> "the actual property value"
-     */
-    public Object resolvePropertyValue(ConfigurableBeanFactory beanFactory, String beanName, String placeholder) {
-        // resolve string value
-        String strVal = beanFactory.resolveEmbeddedValue(placeholder);
-        // 获得 BeanDefinition 对象
-        BeanDefinition bd = (beanFactory.containsBean(beanName) ? beanFactory.getMergedBeanDefinition(beanName) : null);
-        // resolve expressions like "#{systemProperties.myProp}"
-        return evaluateBeanDefinitionString(beanFactory, strVal, bd);
-    }
-
-    private Object evaluateBeanDefinitionString(ConfigurableBeanFactory beanFactory, String value, BeanDefinition beanDefinition) {
-        if (beanFactory.getBeanExpressionResolver() == null) {
-            return value;
-        }
-        Scope scope = (beanDefinition != null ? beanFactory.getRegisteredScope(beanDefinition.getScope()) : null);
-        return beanFactory.getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(beanFactory, scope));
-    }
-
-    /**
-     * Extract keys from placeholder, e.g.
-     * <ul>
-     * <li>${some.key} => "some.key"</li>
-     * <li>${some.key:${some.other.key:100}} => "some.key", "some.other.key"</li>
-     * <li>${${some.key}} => "some.key"</li>
-     * <li>${${some.key:other.key}} => "some.key"</li>
-     * <li>${${some.key}:${another.key}} => "some.key", "another.key"</li>
-     * <li>#{new java.text.SimpleDateFormat('${some.key}').parse('${another.key}')} => "some.key", "another.key"</li>
-     * </ul>
-     */
-    public Set<String> extractPlaceholderKeys(String propertyString) {
-        Set<String> placeholderKeys = Sets.newHashSet();
-
-        if (!isNormalizedPlaceholder(propertyString) && !isExpressionWithPlaceholder(propertyString)) {
-            return placeholderKeys;
-        }
-
-        Stack<String> stack = new Stack<>();
-        stack.push(propertyString);
-
-        while (!stack.isEmpty()) {
-            String strVal = stack.pop();
-            int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
-            if (startIndex == -1) {
-                placeholderKeys.add(strVal);
-                continue;
-            }
-            int endIndex = findPlaceholderEndIndex(strVal, startIndex);
-            if (endIndex == -1) {
-                // invalid placeholder?
-                continue;
-            }
-
-            String placeholderCandidate = strVal.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
-
-            // ${some.key:other.key}
-            if (placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)) {
-                stack.push(placeholderCandidate);
-            } else {
-                // some.key:${some.other.key:100}
-                int separatorIndex = placeholderCandidate.indexOf(VALUE_SEPARATOR);
-
-                if (separatorIndex == -1) {
-                    stack.push(placeholderCandidate);
-                } else {
-                    stack.push(placeholderCandidate.substring(0, separatorIndex));
-                    String defaultValuePart =
-                            normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex + VALUE_SEPARATOR.length()));
-                    if (!Strings.isNullOrEmpty(defaultValuePart)) {
-                        stack.push(defaultValuePart);
-                    }
-                }
-            }
-
-            // has remaining part, e.g. ${a}.${b}
-            if (endIndex + PLACEHOLDER_SUFFIX.length() < strVal.length() - 1) {
-                String remainingPart = normalizeToPlaceholder(strVal.substring(endIndex + PLACEHOLDER_SUFFIX.length()));
-                if (!Strings.isNullOrEmpty(remainingPart)) {
-                    stack.push(remainingPart);
-                }
-            }
-        }
-
-        return placeholderKeys;
-    }
-
-    private boolean isNormalizedPlaceholder(String propertyString) {
-        return propertyString.startsWith(PLACEHOLDER_PREFIX) && propertyString.endsWith(PLACEHOLDER_SUFFIX);
-    }
-
-    private boolean isExpressionWithPlaceholder(String propertyString) {
-        return propertyString.startsWith(EXPRESSION_PREFIX) && propertyString.endsWith(EXPRESSION_SUFFIX)
-                && propertyString.contains(PLACEHOLDER_PREFIX);
-    }
-
-    private String normalizeToPlaceholder(String strVal) {
-        int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
-        if (startIndex == -1) {
-            return null;
-        }
-        int endIndex = strVal.lastIndexOf(PLACEHOLDER_SUFFIX);
-        if (endIndex == -1) {
-            return null;
-        }
-
-        return strVal.substring(startIndex, endIndex + PLACEHOLDER_SUFFIX.length());
-    }
-
-    private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
-        int index = startIndex + PLACEHOLDER_PREFIX.length();
-        int withinNestedPlaceholder = 0;
-        while (index < buf.length()) {
-            if (StringUtils.substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
-                if (withinNestedPlaceholder > 0) {
-                    withinNestedPlaceholder--;
-                    index = index + PLACEHOLDER_SUFFIX.length();
-                } else {
-                    return index;
-                }
-            } else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) {
-                withinNestedPlaceholder++;
-                index = index + SIMPLE_PLACEHOLDER_PREFIX.length();
-            } else {
-                index++;
-            }
-        }
-        return -1;
-    }
-
-}

+ 0 - 72
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/PropertySourcesProcessor.java

@@ -1,72 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.property;
-
-import cn.iocoder.dashboard.framework.apollox.spring.config.ConfigPropertySource;
-import cn.iocoder.dashboard.framework.apollox.spring.config.ConfigPropertySourceFactory;
-import cn.iocoder.dashboard.framework.apollox.spring.util.SpringInjector;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.core.Ordered;
-import org.springframework.core.PriorityOrdered;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.Environment;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Apollo Property Sources processor for Spring Annotation Based Application. <br /> <br />
- * <p>
- * The reason why PropertySourcesProcessor implements {@link BeanFactoryPostProcessor} instead of
- * {@link org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor} is that lower versions of
- * Spring (e.g. 3.1.1) doesn't support registering BeanDefinitionRegistryPostProcessor in ImportBeanDefinitionRegistrar
- * - {@link com.ctrip.framework.apollo.spring.annotation.ApolloConfigRegistrar}
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered {
-
-    /**
-     * 是否初始化的标识
-     */
-    private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);
-
-    private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector.getInstance(ConfigPropertySourceFactory.class);
-    /**
-     * Spring ConfigurableEnvironment 对象
-     */
-    private ConfigurableEnvironment environment;
-
-
-    @Override
-    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-        if (INITIALIZED.compareAndSet(false, true)) {
-            // 初始化 AutoUpdateConfigChangeListener 对象,实现属性的自动更新
-            initializeAutoUpdatePropertiesFeature(beanFactory);
-        }
-    }
-
-    private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) {
-        // 创建 AutoUpdateConfigChangeListener 对象
-        AutoUpdateConfigChangeListener autoUpdateConfigChangeListener = new AutoUpdateConfigChangeListener(environment, beanFactory);
-        // 循环,向 ConfigPropertySource 注册配置变更器
-        List<ConfigPropertySource> configPropertySources = configPropertySourceFactory.getAllConfigPropertySources();
-        for (ConfigPropertySource configPropertySource : configPropertySources) {
-            configPropertySource.addChangeListener(autoUpdateConfigChangeListener);
-        }
-    }
-
-    @Override
-    public void setEnvironment(Environment environment) {
-        //it is safe enough to cast as all known environment is derived from ConfigurableEnvironment
-        this.environment = (ConfigurableEnvironment) environment;
-    }
-
-    @Override
-    public int getOrder() {
-        // make it as early as possible
-        return Ordered.HIGHEST_PRECEDENCE; // 最高优先级
-    }
-
-}

+ 0 - 152
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValue.java

@@ -1,152 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.property;
-
-import org.springframework.core.MethodParameter;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-
-/**
- * Spring @Value method info
- *
- * @author github.com/zhegexiaohuozi  seimimaster@gmail.com
- * @since 2018/2/6.
- */
-public class SpringValue {
-
-    /**
-     * Bean 对象
-     */
-    private Object bean;
-    /**
-     * Bean 名字
-     */
-    private String beanName;
-    /**
-     * Spring 方法参数封装
-     */
-    private MethodParameter methodParameter;
-    /**
-     * Field
-     */
-    private Field field;
-    /**
-     * KEY
-     *
-     * 即在 Config 中的属性 KEY 。
-     */
-    private String key;
-    /**
-     * 占位符
-     */
-    private String placeholder;
-    /**
-     * 值类型
-     */
-    private Class<?> targetType;
-    /**
-     * 是否 JSON
-     */
-    private boolean isJson;
-    /**
-     * 泛型。当是 JSON 类型时,使用
-     */
-    private Type genericType;
-
-    // Field
-    public SpringValue(String key, String placeholder, Object bean, String beanName, Field field, boolean isJson) {
-        this.bean = bean;
-        this.beanName = beanName;
-        // Field
-        this.field = field;
-        this.key = key;
-        this.placeholder = placeholder;
-        // Field 差异
-        this.targetType = field.getType();
-        this.isJson = isJson;
-        if (isJson) {
-            this.genericType = field.getGenericType();
-        }
-    }
-
-    // Method
-    public SpringValue(String key, String placeholder, Object bean, String beanName, Method method, boolean isJson) {
-        this.bean = bean;
-        this.beanName = beanName;
-        // Method
-        this.methodParameter = new MethodParameter(method, 0);
-        this.key = key;
-        this.placeholder = placeholder;
-        // Method 差异
-        Class<?>[] paramTps = method.getParameterTypes();
-        this.targetType = paramTps[0];
-        this.isJson = isJson;
-        if (isJson) {
-            this.genericType = method.getGenericParameterTypes()[0];
-        }
-    }
-
-    public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
-        // Field
-        if (isField()) {
-            injectField(newVal);
-        // Method
-        } else {
-            injectMethod(newVal);
-        }
-    }
-
-    private void injectField(Object newVal) throws IllegalAccessException {
-        boolean accessible = field.isAccessible();
-        field.setAccessible(true);
-        field.set(bean, newVal);
-        field.setAccessible(accessible);
-    }
-
-    private void injectMethod(Object newVal) throws InvocationTargetException, IllegalAccessException {
-        methodParameter.getMethod().invoke(bean, newVal);
-    }
-
-    public String getBeanName() {
-        return beanName;
-    }
-
-    public Class<?> getTargetType() {
-        return targetType;
-    }
-
-    public String getPlaceholder() {
-        return this.placeholder;
-    }
-
-    public MethodParameter getMethodParameter() {
-        return methodParameter;
-    }
-
-    public boolean isField() {
-        return this.field != null;
-    }
-
-    public Field getField() {
-        return field;
-    }
-
-    public Type getGenericType() {
-        return genericType;
-    }
-
-    public boolean isJson() {
-        return isJson;
-    }
-
-    @Override
-    public String toString() {
-        if (isField()) {
-            return String.format("key: %s, beanName: %s, field: %s.%s", key, beanName, bean.getClass().getName(), field.getName());
-        }
-        return String.format("key: %s, beanName: %s, method: %s.%s", key, beanName, bean.getClass().getName(),
-                methodParameter.getMethod().getName());
-    }
-
-}

+ 0 - 28
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValueDefinition.java

@@ -1,28 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.property;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * Spring Value 定义
- */
-@Getter
-@AllArgsConstructor
-public class SpringValueDefinition {
-
-    /**
-     * KEY
-     *
-     * 即在 Config 中的属性 KEY 。
-     */
-    private final String key;
-    /**
-     * 占位符
-     */
-    private final String placeholder;
-    /**
-     * 属性名
-     */
-    private final String propertyName;
-
-}

+ 0 - 94
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValueDefinitionProcessor.java

@@ -1,94 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.property;
-
-import cn.hutool.core.lang.Singleton;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.Multimap;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.MutablePropertyValues;
-import org.springframework.beans.PropertyValue;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.config.TypedStringValue;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
-
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * To process xml config placeholders, e.g.
- *
- * <pre>
- *  &lt;bean class=&quot;com.ctrip.framework.apollo.demo.spring.xmlConfigDemo.bean.XmlBean&quot;&gt;
- *    &lt;property name=&quot;timeout&quot; value=&quot;${timeout:200}&quot;/&gt;
- *    &lt;property name=&quot;batch&quot; value=&quot;${batch:100}&quot;/&gt;
- *  &lt;/bean&gt;
- * </pre>
- */
-public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor {
-
-    /**
-     * SpringValueDefinition 集合
-     * <p>
-     * KEY:beanName
-     * VALUE:SpringValueDefinition 集合
-     */
-    private static final Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions = LinkedListMultimap.create();
-    /**
-     * 是否初始化的标识
-     */
-    private static final AtomicBoolean initialized = new AtomicBoolean(false);
-
-    private final PlaceholderHelper placeholderHelper = Singleton.get(PlaceholderHelper.class);
-
-    @Override
-    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
-        processPropertyValues(registry);
-    }
-
-    @Override
-    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-    }
-
-    public static Multimap<String, SpringValueDefinition> getBeanName2SpringValueDefinitions() {
-        return beanName2SpringValueDefinitions;
-    }
-
-    private void processPropertyValues(BeanDefinitionRegistry beanRegistry) {
-        // 若已经初始化,直接返回
-        if (!initialized.compareAndSet(false, true)) {
-            // already initialized
-            return;
-        }
-        // 循环 BeanDefinition 集合
-        String[] beanNames = beanRegistry.getBeanDefinitionNames();
-        for (String beanName : beanNames) {
-            BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName);
-            // 循环 BeanDefinition 的 PropertyValue 数组
-            MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues();
-            List<PropertyValue> propertyValues = mutablePropertyValues.getPropertyValueList();
-            for (PropertyValue propertyValue : propertyValues) {
-                // 获得 `value` 属性。
-                Object value = propertyValue.getValue();
-                // 忽略非 Spring PlaceHolder 的 `value` 属性。
-                if (!(value instanceof TypedStringValue)) {
-                    continue;
-                }
-                // 获得 `placeholder` 属性。
-                String placeholder = ((TypedStringValue) value).getValue();
-                // 提取 `keys` 属性们。
-                Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
-                if (keys.isEmpty()) {
-                    continue;
-                }
-                // 循环 `keys` ,创建对应的 SpringValueDefinition 对象,并添加到 `beanName2SpringValueDefinitions` 中。
-                for (String key : keys) {
-                    beanName2SpringValueDefinitions.put(beanName,
-                            new SpringValueDefinition(key, placeholder, propertyValue.getName()));
-                }
-            }
-        }
-    }
-
-}

+ 0 - 31
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/property/SpringValueRegistry.java

@@ -1,31 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.property;
-
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.Multimap;
-
-import java.util.Collection;
-
-/**
- * {@link SpringValue} 注册表
- */
-public class SpringValueRegistry {
-
-    /**
-     * SpringValue 集合
-     *
-     * KEY:属性 KEY ,即 Config 配置 KEY
-     * VALUE:SpringValue 数组
-     */
-    private final Multimap<String, SpringValue> registry = LinkedListMultimap.create();
-
-    // 注册
-    public void register(String key, SpringValue springValue) {
-        registry.put(key, springValue);
-    }
-
-    // 获得
-    public Collection<SpringValue> get(String key) {
-        return registry.get(key);
-    }
-
-}

+ 0 - 38
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/util/BeanRegistrationUtil.java

@@ -1,38 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.util;
-
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-
-import java.util.Objects;
-
-/**
- * Bean Registration 工具类
- *
- * @author Jason Song(song_s@ctrip.com)
- */
-public class BeanRegistrationUtil {
-
-    // 注册 `beanClass` 到 BeanDefinitionRegistry 中,当且仅当 `beanName` 和 `beanClass` 都不存在对应的 BeanDefinition 时
-    public static boolean registerBeanDefinitionIfNotExists(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass) {
-        // 不存在 `beanName` 对应的 BeanDefinition
-        if (registry.containsBeanDefinition(beanName)) {
-            return false;
-        }
-
-        // 不存在 `beanClass` 对应的 BeanDefinition
-        String[] candidates = registry.getBeanDefinitionNames();
-        for (String candidate : candidates) {
-            BeanDefinition beanDefinition = registry.getBeanDefinition(candidate);
-            if (Objects.equals(beanDefinition.getBeanClassName(), beanClass.getName())) {
-                return false;
-            }
-        }
-
-        // 注册 `beanClass` 到 BeanDefinitionRegistry 中
-        BeanDefinition annotationProcessor = BeanDefinitionBuilder.genericBeanDefinition(beanClass).getBeanDefinition();
-        registry.registerBeanDefinition(beanName, annotationProcessor);
-        return true;
-    }
-
-}

+ 0 - 14
src/main/java/cn/iocoder/dashboard/framework/apollox/spring/util/SpringInjector.java

@@ -1,14 +0,0 @@
-package cn.iocoder.dashboard.framework.apollox.spring.util;
-
-import cn.hutool.core.lang.Singleton;
-
-/**
- * Spring 注入器
- */
-public class SpringInjector {
-
-    public static <T> T getInstance(Class<T> clazz) {
-        return Singleton.get(clazz);
-    }
-
-}

+ 0 - 4
src/main/resources/META-INF/spring.factories

@@ -1,4 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-    cn.iocoder.dashboard.framework.apollox.spring.boot.ApolloAutoConfiguration
-org.springframework.context.ApplicationContextInitializer=\
-    cn.iocoder.dashboard.framework.apollox.spring.boot.ApolloApplicationContextInitializer

+ 2 - 3
src/main/resources/application.yaml

@@ -50,10 +50,9 @@ yudao:
 # Apollo 配置中心
 apollo:
   bootstrap:
-    enabled: true
+    enabled: true # 设置 Apollo 在启动阶段生效
     eagerLoad:
-      enabled: true
-  autoUpdateInjectedSpringProperties: true
+      enabled: true # 设置 Apollo 在日志初始化前生效,可以实现日志的动态级别配置
 
 # MyBatis Plus 的配置项
 mybatis-plus: