Browse Source

实现内嵌的 apollo 的配置中心的支持

YunaiV 4 years ago
parent
commit
c4c614592a

+ 7 - 0
pom.xml

@@ -167,6 +167,13 @@
             <version>${redisson.version}</version>
         </dependency>
 
+        <!-- -->
+        <dependency>
+            <groupId>com.ctrip.framework.apollo</groupId>
+            <artifactId>apollo-client</artifactId>
+            <version>1.7.0</version>
+        </dependency>
+
         <!-- 监控相关 -->
         <dependency>
             <groupId>org.apache.skywalking</groupId>

+ 95 - 0
src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java

@@ -0,0 +1,95 @@
+package cn.iocoder.dashboard.framework.apollo.internals;
+
+import com.ctrip.framework.apollo.Apollo;
+import com.ctrip.framework.apollo.build.ApolloInjector;
+import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
+import com.ctrip.framework.apollo.enums.ConfigSourceType;
+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 lombok.extern.slf4j.Slf4j;
+
+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 {
+
+    private final static ScheduledExecutorService m_executorService;
+
+    static {
+        m_executorService = Executors.newScheduledThreadPool(1,
+                ApolloThreadFactory.create(DBConfigRepository.class.getSimpleName(), true));
+    }
+
+    private final ConfigUtil m_configUtil;
+
+    private final AtomicReference<Properties> m_configCache;
+    private final String m_namespace;
+
+    public DBConfigRepository(String namespace) {
+        // 初始化变量
+        this.m_namespace = namespace;
+        m_configCache = new AtomicReference<>();
+        m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
+
+        // 初始化加载
+        this.trySync();
+        // 初始化定时任务
+        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);
+    }
+
+    @Override
+    public Properties getConfig() {
+        // 兜底,避免可能存在配置为 null 的情况
+        if (m_configCache.get() == null) {
+            this.trySync();
+        }
+        // 返回配置
+        return m_configCache.get();
+    }
+
+    @Override
+    public void setUpstreamRepository(ConfigRepository upstreamConfigRepository) {
+        // 啥事不做
+    }
+
+    @Override
+    public ConfigSourceType getSourceType() {
+        return ConfigSourceType.REMOTE;
+    }
+
+    private void schedulePeriodicRefresh() {
+        log.debug("Schedule periodic refresh with interval: {} {}",
+                m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit());
+        m_executorService.scheduleAtFixedRate(() -> {
+            Tracer.logEvent("Apollo.ConfigService", String.format("periodicRefresh: %s", m_namespace));
+            log.debug("refresh config for namespace: {}", m_namespace);
+
+            // 执行同步
+            trySync();
+
+            Tracer.logEvent("Apollo.Client.Version", Apollo.VERSION);
+        }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
+                m_configUtil.getRefreshIntervalTimeUnit());
+//                TimeUnit.SECONDS);
+    }
+
+}

+ 75 - 0
src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DefaultXInjector.java

@@ -0,0 +1,75 @@
+package cn.iocoder.dashboard.framework.apollo.internals;
+
+import cn.iocoder.dashboard.framework.apollo.spi.DBConfigFactory;
+import com.ctrip.framework.apollo.exceptions.ApolloConfigException;
+import com.ctrip.framework.apollo.internals.*;
+import com.ctrip.framework.apollo.spi.*;
+import com.ctrip.framework.apollo.tracer.Tracer;
+import com.ctrip.framework.apollo.util.ConfigUtil;
+import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory;
+import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
+import com.ctrip.framework.apollo.util.http.HttpUtil;
+import com.ctrip.framework.apollo.util.yaml.YamlParser;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Singleton;
+
+/**
+ * Guice injector
+ *
+ * 基于 Guice 注入器实现类
+ *
+ * @author Jason Song(song_s@ctrip.com)
+ */
+public class DefaultXInjector implements Injector {
+
+    private final com.google.inject.Injector m_injector;
+
+    public DefaultXInjector() {
+        try {
+            m_injector = Guice.createInjector(new ApolloModule());
+        } catch (Throwable ex) {
+            ApolloConfigException exception = new ApolloConfigException("Unable to initialize Guice Injector!", ex);
+            Tracer.logError(exception);
+            throw exception;
+        }
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> clazz) {
+        try {
+            return m_injector.getInstance(clazz);
+        } catch (Throwable ex) {
+            Tracer.logError(ex);
+            throw new ApolloConfigException(String.format("Unable to load instance for %s!", clazz.getName()), ex);
+        }
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> clazz, String name) {
+        // Guice does not support get instance by type and name
+        return null;
+    }
+
+    private static class ApolloModule extends AbstractModule {
+
+        @Override
+        protected void configure() {
+            bind(ConfigManager.class).to(DefaultConfigManager.class).in(Singleton.class);
+            bind(ConfigFactoryManager.class).to(DefaultConfigFactoryManager.class).in(Singleton.class);
+            bind(ConfigRegistry.class).to(DefaultConfigRegistry.class).in(Singleton.class);
+
+            // 自定义 ConfigFactory 实现,使用 DB 作为数据源
+            bind(ConfigFactory.class).to(DBConfigFactory.class).in(Singleton.class);
+
+            bind(ConfigUtil.class).in(Singleton.class);
+            bind(HttpUtil.class).in(Singleton.class);
+            bind(ConfigServiceLocator.class).in(Singleton.class);
+            bind(RemoteConfigLongPollService.class).in(Singleton.class);
+            bind(YamlParser.class).in(Singleton.class);
+            bind(PropertiesFactory.class).to(DefaultPropertiesFactory.class).in(Singleton.class);
+        }
+
+    }
+
+}

+ 1 - 0
src/main/java/cn/iocoder/dashboard/framework/apollo/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.dashboard.framework.apollo;

+ 27 - 0
src/main/java/cn/iocoder/dashboard/framework/apollo/spi/DBConfigFactory.java

@@ -0,0 +1,27 @@
+package cn.iocoder.dashboard.framework.apollo.spi;
+
+import cn.iocoder.dashboard.framework.apollo.internals.DBConfigRepository;
+import com.ctrip.framework.apollo.Config;
+import com.ctrip.framework.apollo.ConfigFile;
+import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
+import com.ctrip.framework.apollo.internals.ConfigRepository;
+import com.ctrip.framework.apollo.internals.DefaultConfig;
+import com.ctrip.framework.apollo.spi.ConfigFactory;
+
+public class DBConfigFactory implements ConfigFactory {
+
+    @Override
+    public Config create(String namespace) {
+        return new DefaultConfig(namespace, this.createDBConfigRepository(namespace));
+    }
+
+    @Override
+    public ConfigFile createConfigFile(String namespace, ConfigFileFormat configFileFormat) {
+        throw new UnsupportedOperationException("暂不支持 Apollo 配置文件");
+    }
+
+    private ConfigRepository createDBConfigRepository(String namespace) {
+        return new DBConfigRepository(namespace); // TODO 芋艿:看看怎么优化
+    }
+
+}

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/controller/config/SysConfigController.java

@@ -28,7 +28,7 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.CO
 @RequestMapping("/system/config")
 public class SysConfigController {
 
-    @Value("${demo.test:false}")
+    @Value("${demo.test}")
     private String demo;
 
     @GetMapping("/demo")

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/permission/SysRoleMapper.java

@@ -8,8 +8,8 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRo
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Mapper;
+import org.springframework.lang.Nullable;
 
-import javax.annotation.Nullable;
 import java.util.Collection;
 import java.util.List;
 

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostService.java

@@ -6,8 +6,8 @@ import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostExport
 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostPageReqVO;
 import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostUpdateReqVO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysPostDO;
+import org.springframework.lang.Nullable;
 
-import javax.annotation.Nullable;
 import java.util.Collection;
 import java.util.List;
 

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionService.java

@@ -1,8 +1,8 @@
 package cn.iocoder.dashboard.modules.system.service.permission;
 
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO;
+import org.springframework.lang.Nullable;
 
-import javax.annotation.Nullable;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleService.java

@@ -6,8 +6,8 @@ import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRole
 import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRolePageReqVO;
 import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleUpdateReqVO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO;
+import org.springframework.lang.Nullable;
 
-import javax.annotation.Nullable;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java

@@ -18,11 +18,11 @@ import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.google.common.collect.ImmutableMap;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 
-import javax.annotation.Nullable;
 import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import java.util.*;

+ 1 - 0
src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector

@@ -0,0 +1 @@
+cn.iocoder.dashboard.framework.apollo.internals.DefaultXInjector

+ 8 - 0
src/main/resources/application.yaml

@@ -47,6 +47,14 @@ yudao:
   file:
     base-path: http://127.0.0.1:1024/api/file/get/
 
+# Apollo 配置中心
+apollo:
+  bootstrap:
+    enabled: true
+    eagerLoad:
+      enabled: true
+  autoUpdateInjectedSpringProperties: true
+
 # MyBatis Plus 的配置项
 mybatis-plus:
   configuration: