mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-28 16:58:43 +08:00 
			
		
		
		
	【移除】Apollo 配置中心,简化学习成本
This commit is contained in:
		| @@ -28,7 +28,6 @@ | |||||||
|         <dynamic-datasource.version>3.5.2</dynamic-datasource.version> |         <dynamic-datasource.version>3.5.2</dynamic-datasource.version> | ||||||
|         <redisson.version>3.17.7</redisson.version> |         <redisson.version>3.17.7</redisson.version> | ||||||
|         <!-- Config 配置中心相关 --> |         <!-- Config 配置中心相关 --> | ||||||
|         <apollo.version>2.0.1</apollo.version> |  | ||||||
|         <!-- 服务保障相关 --> |         <!-- 服务保障相关 --> | ||||||
|         <lock4j.version>2.2.2</lock4j.version> |         <lock4j.version>2.2.2</lock4j.version> | ||||||
|         <resilience4j.version>1.7.1</resilience4j.version> |         <resilience4j.version>1.7.1</resilience4j.version> | ||||||
| @@ -224,17 +223,6 @@ | |||||||
|             </dependency> |             </dependency> | ||||||
|  |  | ||||||
|             <!-- Config 配置中心相关 --> |             <!-- Config 配置中心相关 --> | ||||||
|             <dependency> |  | ||||||
|                 <groupId>cn.iocoder.boot</groupId> |  | ||||||
|                 <artifactId>yudao-spring-boot-starter-config</artifactId> |  | ||||||
|                 <version>${revision}</version> |  | ||||||
|             </dependency> |  | ||||||
|  |  | ||||||
|             <dependency> |  | ||||||
|                 <groupId>com.ctrip.framework.apollo</groupId> |  | ||||||
|                 <artifactId>apollo-client</artifactId> <!-- 引入 Apollo Client 库,实现内嵌的配置中心 --> |  | ||||||
|                 <version>${apollo.version}</version> |  | ||||||
|             </dependency> |  | ||||||
|  |  | ||||||
|             <!-- Job 定时任务相关 --> |             <!-- Job 定时任务相关 --> | ||||||
|             <dependency> |             <dependency> | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ | |||||||
|         <module>yudao-spring-boot-starter-file</module> |         <module>yudao-spring-boot-starter-file</module> | ||||||
|         <module>yudao-spring-boot-starter-monitor</module> |         <module>yudao-spring-boot-starter-monitor</module> | ||||||
|         <module>yudao-spring-boot-starter-protection</module> |         <module>yudao-spring-boot-starter-protection</module> | ||||||
|         <module>yudao-spring-boot-starter-config</module> |  | ||||||
|         <module>yudao-spring-boot-starter-job</module> |         <module>yudao-spring-boot-starter-job</module> | ||||||
|         <module>yudao-spring-boot-starter-mq</module> |         <module>yudao-spring-boot-starter-mq</module> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,37 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" |  | ||||||
|          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <parent> |  | ||||||
|         <groupId>cn.iocoder.boot</groupId> |  | ||||||
|         <artifactId>yudao-framework</artifactId> |  | ||||||
|         <version>${revision}</version> |  | ||||||
|     </parent> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|     <artifactId>yudao-spring-boot-starter-config</artifactId> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>${project.artifactId}</name> |  | ||||||
|     <description>配置中心,基于 Apollo 魔改实现</description> |  | ||||||
|     <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |  | ||||||
|  |  | ||||||
|     <dependencies> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>cn.iocoder.boot</groupId> |  | ||||||
|             <artifactId>yudao-common</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|  |  | ||||||
|         <!-- Spring 核心 --> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>org.springframework.boot</groupId> |  | ||||||
|             <artifactId>spring-boot-starter</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|  |  | ||||||
|         <!-- Config 配置中心相关 --> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>com.ctrip.framework.apollo</groupId> |  | ||||||
|             <artifactId>apollo-client</artifactId> <!-- 引入 Apollo Client 库,实现内嵌的配置中心 --> |  | ||||||
|         </dependency> |  | ||||||
|     </dependencies> |  | ||||||
|  |  | ||||||
| </project> |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| package cn.iocoder.yudao.framework.apollo.core; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.apollo.internals.ConfigFrameworkDAO; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 针对 {@link com.ctrip.framework.apollo.core.ConfigConsts} 的补充,主要增加: |  | ||||||
|  * |  | ||||||
|  * 1. apollo.jdbc.* 配置项的枚举 |  | ||||||
|  * |  | ||||||
|  * @author 芋道源码 |  | ||||||
|  */ |  | ||||||
| public class ConfigConsts { |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * {@link ConfigFrameworkDAO} 的实现类 |  | ||||||
|      */ |  | ||||||
|     public static final String APOLLO_JDBC_DAO = "apollo.jdbc.dao"; |  | ||||||
|     public static final String APOLLO_JDBC_URL = "apollo.jdbc.url"; |  | ||||||
|     public static final String APOLLO_JDBC_USERNAME = "apollo.jdbc.username"; |  | ||||||
|     public static final String APOLLO_JDBC_PASSWORD = "apollo.jdbc.password"; |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| package cn.iocoder.yudao.framework.apollo.internals; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.apollo.internals.dto.ConfigRespDTO; |  | ||||||
|  |  | ||||||
| import java.time.LocalDateTime; |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 配置 Framework DAO 接口 |  | ||||||
|  * |  | ||||||
|  * 注意,实现类必须提供 (String jdbcUrl, String username, String password) 构造方法 |  | ||||||
|  * |  | ||||||
|  * @author 芋道源码 |  | ||||||
|  */ |  | ||||||
| public interface ConfigFrameworkDAO { |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 查询是否存在比 maxUpdateTime 的更新记录数量 |  | ||||||
|      * |  | ||||||
|      * @param maxUpdateTime 最大更新时间 |  | ||||||
|      * @return 是否存在 |  | ||||||
|      */ |  | ||||||
|     int selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime); |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 查询配置列表 |  | ||||||
|      * |  | ||||||
|      * @return 配置列表 |  | ||||||
|      */ |  | ||||||
|     List<ConfigRespDTO> selectList(); |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,183 +0,0 @@ | |||||||
| package cn.iocoder.yudao.framework.apollo.internals; |  | ||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; |  | ||||||
| import cn.hutool.core.util.ClassUtil; |  | ||||||
| import cn.hutool.core.util.ReflectUtil; |  | ||||||
| import cn.iocoder.yudao.framework.apollo.core.ConfigConsts; |  | ||||||
| import cn.iocoder.yudao.framework.apollo.internals.dto.ConfigRespDTO; |  | ||||||
| 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 com.ctrip.framework.apollo.util.factory.PropertiesFactory; |  | ||||||
| import lombok.SneakyThrows; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
|  |  | ||||||
| import java.lang.reflect.Constructor; |  | ||||||
| import java.time.LocalDateTime; |  | ||||||
| import java.util.Comparator; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Properties; |  | ||||||
| import java.util.concurrent.Executors; |  | ||||||
| import java.util.concurrent.ScheduledExecutorService; |  | ||||||
|  |  | ||||||
| @Slf4j |  | ||||||
| public class DBConfigRepository extends AbstractConfigRepository { |  | ||||||
|  |  | ||||||
|     private final static ScheduledExecutorService m_executorService; |  | ||||||
|  |  | ||||||
|     private static DBConfigRepository INSTANCE; |  | ||||||
|  |  | ||||||
|     static { |  | ||||||
|         m_executorService = Executors.newScheduledThreadPool(1, |  | ||||||
|                 ApolloThreadFactory.create(DBConfigRepository.class.getSimpleName(), true)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private final ConfigUtil m_configUtil; |  | ||||||
|     private final PropertiesFactory propertiesFactory; |  | ||||||
|     private final String m_namespace; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 配置缓存,使用 Properties 存储 |  | ||||||
|      */ |  | ||||||
|     private volatile Properties m_configCache; |  | ||||||
|     /** |  | ||||||
|      * 缓存配置的最大更新时间,用于后续的增量轮询,判断是否有更新 |  | ||||||
|      */ |  | ||||||
|     private volatile LocalDateTime maxUpdateTime; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 配置读取 DAO |  | ||||||
|      */ |  | ||||||
|     private final ConfigFrameworkDAO configFrameworkDAO; |  | ||||||
|  |  | ||||||
|     public DBConfigRepository(String namespace) { |  | ||||||
|         // 初始化变量 |  | ||||||
|         this.m_namespace = namespace; |  | ||||||
|         this.propertiesFactory = ApolloInjector.getInstance(PropertiesFactory.class); |  | ||||||
|         this.m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); |  | ||||||
|         // 初始化 DB |  | ||||||
|         this.configFrameworkDAO = createConfigFrameworkDAO(); |  | ||||||
|  |  | ||||||
|         // 初始化加载 |  | ||||||
|         this.trySync(); |  | ||||||
|         // 初始化定时任务 |  | ||||||
|         this.schedulePeriodicRefresh(); |  | ||||||
|  |  | ||||||
|         // 设置单例 |  | ||||||
|         INSTANCE = this; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @SneakyThrows |  | ||||||
|     private static ConfigFrameworkDAO createConfigFrameworkDAO() { |  | ||||||
|         String dao = System.getProperty(ConfigConsts.APOLLO_JDBC_DAO); |  | ||||||
|         String url = System.getProperty(ConfigConsts.APOLLO_JDBC_URL); |  | ||||||
|         String username = System.getProperty(ConfigConsts.APOLLO_JDBC_USERNAME); |  | ||||||
|         String password = System.getProperty(ConfigConsts.APOLLO_JDBC_PASSWORD); |  | ||||||
|         // 创建 DBConfigRepository 对象 |  | ||||||
|         Class<? extends ConfigFrameworkDAO> clazz = ClassUtil.loadClass(dao); |  | ||||||
|         Constructor<? extends ConfigFrameworkDAO> constructor = ReflectUtil.getConstructor(clazz, String.class, String.class, String.class); |  | ||||||
|         return constructor.newInstance(url, username, password); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 通知同步, |  | ||||||
|      */ |  | ||||||
|     public static void noticeSync() { |  | ||||||
|         // 提交到线程池中,避免和 schedulePeriodicRefresh 并发问题 |  | ||||||
|         m_executorService.submit(() -> { |  | ||||||
|             INSTANCE.trySync(); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected void sync() { |  | ||||||
|         // 第一步,尝试获取配置 |  | ||||||
|         List<ConfigRespDTO> configs = this.loadConfigIfUpdate(this.maxUpdateTime); |  | ||||||
|         if (CollUtil.isEmpty(configs)) { // 如果没有更新,则返回 |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 第二步,构建新的 Properties |  | ||||||
|         Properties newProperties = this.buildProperties(configs); |  | ||||||
|         this.m_configCache = newProperties; |  | ||||||
|         // 第三步,获取最大的配置时间 |  | ||||||
|         assert configs.size() > 0; // 断言,避免告警 |  | ||||||
|         this.maxUpdateTime = configs.stream().max(Comparator.comparing(ConfigRespDTO::getUpdateTime)).get().getUpdateTime(); |  | ||||||
|         // 第四部,触发配置刷新!重要!!!! |  | ||||||
|         super.fireRepositoryChange(m_namespace, newProperties); |  | ||||||
|         log.info("[sync][缓存配置,数量为:{}]", configs.size()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Properties getConfig() { |  | ||||||
|         // 兜底,避免可能存在配置为 null 的情况 |  | ||||||
|         if (m_configCache == null) { |  | ||||||
|             this.trySync(); |  | ||||||
|         } |  | ||||||
|         // 返回配置 |  | ||||||
|         return m_configCache; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void setUpstreamRepository(ConfigRepository upstreamConfigRepository) { |  | ||||||
|         // 啥事不做 |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public ConfigSourceType getSourceType() { |  | ||||||
|         return ConfigSourceType.REMOTE; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Properties buildProperties(List<ConfigRespDTO> configs) { |  | ||||||
|         Properties properties = propertiesFactory.getPropertiesInstance(); |  | ||||||
|         configs.stream().filter(config -> !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()); |  | ||||||
|         m_executorService.scheduleAtFixedRate(() -> { |  | ||||||
|             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); |  | ||||||
|         }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), |  | ||||||
|                 m_configUtil.getRefreshIntervalTimeUnit()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // ========== 数据库相关操作 ========== |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 如果配置发生变化,从数据库中获取最新的全量配置。 |  | ||||||
|      * 如果未发生变化,则返回空 |  | ||||||
|      * |  | ||||||
|      * @param maxUpdateTime 当前配置的最大更新时间 |  | ||||||
|      * @return 配置列表 |  | ||||||
|      */ |  | ||||||
|     private List<ConfigRespDTO> loadConfigIfUpdate(LocalDateTime maxUpdateTime) { |  | ||||||
|         // 第一步,判断是否要更新。 |  | ||||||
|         if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 |  | ||||||
|             log.info("[loadConfigIfUpdate][首次加载全量配置]"); |  | ||||||
|         } else { // 判断数据库中是否有更新的配置 |  | ||||||
|             if (configFrameworkDAO.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { |  | ||||||
|                 return null; |  | ||||||
|             } |  | ||||||
|             log.info("[loadConfigIfUpdate][增量加载全量配置]"); |  | ||||||
|         } |  | ||||||
|         // 第二步,如果有更新,则从数据库加载所有配置 |  | ||||||
|         return configFrameworkDAO.selectList(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,75 +0,0 @@ | |||||||
| package cn.iocoder.yudao.framework.apollo.internals; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.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.DefaultHttpClient; |  | ||||||
| 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(DefaultHttpClient.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,33 +0,0 @@ | |||||||
| package cn.iocoder.yudao.framework.apollo.internals.dto; |  | ||||||
|  |  | ||||||
| import lombok.Data; |  | ||||||
|  |  | ||||||
| import java.time.LocalDateTime; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 配置 Response DTO |  | ||||||
|  * |  | ||||||
|  * @author 芋道源码 |  | ||||||
|  */ |  | ||||||
| @Data |  | ||||||
| public class ConfigRespDTO { |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 参数键名 |  | ||||||
|      */ |  | ||||||
|     private String key; |  | ||||||
|     /** |  | ||||||
|      * 参数键值 |  | ||||||
|      */ |  | ||||||
|     private String value; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 是否删除 |  | ||||||
|      */ |  | ||||||
|     private Boolean deleted; |  | ||||||
|     /** |  | ||||||
|      * 更新时间 |  | ||||||
|      */ |  | ||||||
|     private LocalDateTime updateTime; |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| /** |  | ||||||
|  * 配置中心客户端,基于 Apollo Client 进行简化 |  | ||||||
|  * |  | ||||||
|  * 差别在于,我们使用 cn.iocoder.yudao.modules.infra.dal.dataobject.config.InfConfigDO 表作为配置源。 |  | ||||||
|  * 当然,功能肯定也会相对少些,满足最小化诉求。 |  | ||||||
|  * |  | ||||||
|  * 1. 项目初始化时,可以使用 SysConfigDO 表的配置 |  | ||||||
|  * 2. 使用 Spring @Value 可以注入属性 |  | ||||||
|  * 3. SysConfigDO 表的配置修改时,注入到 @Value 的属性可以刷新 |  | ||||||
|  * |  | ||||||
|  * 另外,整个包结构会参考 Apollo 为主,方便维护与理解 |  | ||||||
|  */ |  | ||||||
| package cn.iocoder.yudao.framework.apollo; |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| package cn.iocoder.yudao.framework.apollo.spi; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.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; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 基于 DB 的 ConfigFactory 实现类 |  | ||||||
|  * |  | ||||||
|  * @author 芋道源码 |  | ||||||
|  */ |  | ||||||
| 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); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,63 +0,0 @@ | |||||||
| package cn.iocoder.yudao.framework.apollo.spring.boot; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.apollo.core.ConfigConsts; |  | ||||||
| import com.google.common.base.Strings; |  | ||||||
| import org.springframework.boot.SpringApplication; |  | ||||||
| import org.springframework.boot.env.EnvironmentPostProcessor; |  | ||||||
| import org.springframework.core.Ordered; |  | ||||||
| import org.springframework.core.env.ConfigurableEnvironment; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 对 {@link com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer} 的补充,目前的目的有: |  | ||||||
|  * |  | ||||||
|  * 1. 将自定义的 apollo.jdbc 设置到 System 变量中 |  | ||||||
|  * |  | ||||||
|  * @author 芋道源码 |  | ||||||
|  */ |  | ||||||
| public class ApolloApplicationContextInitializer implements EnvironmentPostProcessor, Ordered { |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 优先级更高,要早于 Apollo 的 ApolloApplicationContextInitializer 的初始化 |  | ||||||
|      */ |  | ||||||
|     public static final int DEFAULT_ORDER = -1; |  | ||||||
|  |  | ||||||
|     private int order = DEFAULT_ORDER; |  | ||||||
|  |  | ||||||
|     private static final String[] APOLLO_SYSTEM_PROPERTIES = {ConfigConsts.APOLLO_JDBC_DAO, |  | ||||||
|             ConfigConsts.APOLLO_JDBC_URL, ConfigConsts.APOLLO_JDBC_USERNAME, ConfigConsts.APOLLO_JDBC_PASSWORD}; |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { |  | ||||||
|         initializeSystemProperty(environment); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * To fill system properties from environment config |  | ||||||
|      */ |  | ||||||
|     void initializeSystemProperty(ConfigurableEnvironment environment) { |  | ||||||
|         for (String propertyName : APOLLO_SYSTEM_PROPERTIES) { |  | ||||||
|             fillSystemPropertyFromEnvironment(environment, propertyName); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environment, String propertyName) { |  | ||||||
|         if (System.getProperty(propertyName) != null) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         String propertyValue = environment.getProperty(propertyName); |  | ||||||
|         if (Strings.isNullOrEmpty(propertyValue)) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         System.setProperty(propertyName, propertyValue); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public int getOrder() { |  | ||||||
|         return order; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setOrder(int order) { |  | ||||||
|         this.order = order; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| cn.iocoder.yudao.framework.apollo.internals.DefaultXInjector |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| org.springframework.boot.env.EnvironmentPostProcessor=\ |  | ||||||
|     cn.iocoder.yudao.framework.apollo.spring.boot.ApolloApplicationContextInitializer |  | ||||||
| @@ -58,10 +58,6 @@ | |||||||
|         </dependency> |         </dependency> | ||||||
|  |  | ||||||
|         <!-- Config 配置中心相关 --> |         <!-- Config 配置中心相关 --> | ||||||
|         <dependency> |  | ||||||
|             <groupId>cn.iocoder.boot</groupId> |  | ||||||
|             <artifactId>yudao-spring-boot-starter-config</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|  |  | ||||||
|         <!-- Job 定时任务相关 --> |         <!-- Job 定时任务相关 --> | ||||||
|         <dependency> |         <dependency> | ||||||
|   | |||||||
| @@ -1,42 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.infra.dal.mysql.config; |  | ||||||
|  |  | ||||||
| import cn.hutool.core.date.LocalDateTimeUtil; |  | ||||||
| import cn.iocoder.yudao.framework.apollo.internals.ConfigFrameworkDAO; |  | ||||||
| import cn.iocoder.yudao.framework.apollo.internals.dto.ConfigRespDTO; |  | ||||||
| import org.springframework.jdbc.core.JdbcTemplate; |  | ||||||
| import org.springframework.jdbc.datasource.DriverManagerDataSource; |  | ||||||
|  |  | ||||||
| import javax.sql.DataSource; |  | ||||||
| import java.time.LocalDateTime; |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * ConfigDAOImpl 实现类 |  | ||||||
|  * |  | ||||||
|  * @author 芋道源码 |  | ||||||
|  */ |  | ||||||
| public class ConfigDAOImpl implements ConfigFrameworkDAO { |  | ||||||
|  |  | ||||||
|     private final JdbcTemplate jdbcTemplate; |  | ||||||
|  |  | ||||||
|     public ConfigDAOImpl(String jdbcUrl, String username, String password) { |  | ||||||
|         DataSource dataSource = new DriverManagerDataSource(jdbcUrl, username, password); |  | ||||||
|         this.jdbcTemplate = new JdbcTemplate(dataSource); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public int selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime) { |  | ||||||
|         return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM infra_config WHERE update_time > ?", |  | ||||||
|                 Integer.class, maxUpdateTime); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public List<ConfigRespDTO> selectList() { |  | ||||||
|         return jdbcTemplate.query("SELECT config_key, value, update_time, deleted FROM infra_config", |  | ||||||
|                 (rs, rowNum) -> new ConfigRespDTO().setKey(rs.getString("config_key")) |  | ||||||
|                         .setValue(rs.getString("value")) |  | ||||||
|                         .setUpdateTime(LocalDateTimeUtil.of(rs.getDate("update_time"))) |  | ||||||
|                         .setDeleted(rs.getBoolean("deleted"))); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,24 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.infra.mq.consumer.config; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.apollo.internals.DBConfigRepository; |  | ||||||
| import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; |  | ||||||
| import cn.iocoder.yudao.module.infra.mq.message.config.ConfigRefreshMessage; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 针对 {@link ConfigRefreshMessage} 的消费者 |  | ||||||
|  * |  | ||||||
|  * @author 芋道源码 |  | ||||||
|  */ |  | ||||||
| @Component |  | ||||||
| @Slf4j |  | ||||||
| public class ConfigRefreshConsumer extends AbstractChannelMessageListener<ConfigRefreshMessage> { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onMessage(ConfigRefreshMessage message) { |  | ||||||
|         log.info("[onMessage][收到 Config 刷新消息]"); |  | ||||||
|         DBConfigRepository.noticeSync(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | /** | ||||||
|  |  * 占位符,避免缩进 | ||||||
|  |  */ | ||||||
|  | package cn.iocoder.yudao.module.infra.mq.consumer; | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.infra.mq.message.config; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; |  | ||||||
| import lombok.Data; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 配置数据刷新 Message |  | ||||||
|  */ |  | ||||||
| @Data |  | ||||||
| public class ConfigRefreshMessage extends AbstractChannelMessage { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public String getChannel() { |  | ||||||
|         return "infra.config.refresh"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | /** | ||||||
|  |  * 占位符,避免缩进 | ||||||
|  |  */ | ||||||
|  | package cn.iocoder.yudao.module.infra.mq.message; | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.infra.mq.producer.config; |  | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.module.infra.mq.message.config.ConfigRefreshMessage; |  | ||||||
| import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
|  |  | ||||||
| import javax.annotation.Resource; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Config 配置相关消息的 Producer |  | ||||||
|  */ |  | ||||||
| @Component |  | ||||||
| public class ConfigProducer { |  | ||||||
|  |  | ||||||
|     @Resource |  | ||||||
|     private RedisMQTemplate redisMQTemplate; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 发送 {@link ConfigRefreshMessage} 消息 |  | ||||||
|      */ |  | ||||||
|     public void sendConfigRefreshMessage() { |  | ||||||
|         ConfigRefreshMessage message = new ConfigRefreshMessage(); |  | ||||||
|         redisMQTemplate.send(message); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | /** | ||||||
|  |  * 占位符,避免缩进 | ||||||
|  |  */ | ||||||
|  | package cn.iocoder.yudao.module.infra.mq.producer; | ||||||
| @@ -1,7 +1,6 @@ | |||||||
| package cn.iocoder.yudao.module.infra.service.config; | package cn.iocoder.yudao.module.infra.service.config; | ||||||
|  |  | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
| import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |  | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigCreateReqVO; | import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigCreateReqVO; | ||||||
| import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigExportReqVO; | import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigExportReqVO; | ||||||
| @@ -12,7 +11,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO; | |||||||
| import cn.iocoder.yudao.module.infra.dal.mysql.config.ConfigMapper; | import cn.iocoder.yudao.module.infra.dal.mysql.config.ConfigMapper; | ||||||
| import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants; | import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants; | ||||||
| import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum; | import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum; | ||||||
| import cn.iocoder.yudao.module.infra.mq.producer.config.ConfigProducer; |  | ||||||
| import com.google.common.annotations.VisibleForTesting; | import com.google.common.annotations.VisibleForTesting; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| @@ -21,6 +19,8 @@ import org.springframework.validation.annotation.Validated; | |||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 参数配置 Service 实现类 |  * 参数配置 Service 实现类 | ||||||
|  */ |  */ | ||||||
| @@ -32,9 +32,6 @@ public class ConfigServiceImpl implements ConfigService { | |||||||
|     @Resource |     @Resource | ||||||
|     private ConfigMapper configMapper; |     private ConfigMapper configMapper; | ||||||
|  |  | ||||||
|     @Resource |  | ||||||
|     private ConfigProducer configProducer; |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public Long createConfig(ConfigCreateReqVO reqVO) { |     public Long createConfig(ConfigCreateReqVO reqVO) { | ||||||
|         // 校验正确性 |         // 校验正确性 | ||||||
| @@ -43,8 +40,6 @@ public class ConfigServiceImpl implements ConfigService { | |||||||
|         ConfigDO config = ConfigConvert.INSTANCE.convert(reqVO); |         ConfigDO config = ConfigConvert.INSTANCE.convert(reqVO); | ||||||
|         config.setType(ConfigTypeEnum.CUSTOM.getType()); |         config.setType(ConfigTypeEnum.CUSTOM.getType()); | ||||||
|         configMapper.insert(config); |         configMapper.insert(config); | ||||||
|         // 发送刷新消息 |  | ||||||
|         configProducer.sendConfigRefreshMessage(); |  | ||||||
|         return config.getId(); |         return config.getId(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -54,9 +49,7 @@ public class ConfigServiceImpl implements ConfigService { | |||||||
|         checkCreateOrUpdate(reqVO.getId(), null); // 不允许更新 key |         checkCreateOrUpdate(reqVO.getId(), null); // 不允许更新 key | ||||||
|         // 更新参数配置 |         // 更新参数配置 | ||||||
|         ConfigDO updateObj = ConfigConvert.INSTANCE.convert(reqVO); |         ConfigDO updateObj = ConfigConvert.INSTANCE.convert(reqVO); | ||||||
|         configMapper.updateById(updateObj); |         configMapper.updateById(updateObj);; | ||||||
|         // 发送刷新消息 |  | ||||||
|         configProducer.sendConfigRefreshMessage(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -65,12 +58,10 @@ public class ConfigServiceImpl implements ConfigService { | |||||||
|         ConfigDO config = checkConfigExists(id); |         ConfigDO config = checkConfigExists(id); | ||||||
|         // 内置配置,不允许删除 |         // 内置配置,不允许删除 | ||||||
|         if (ConfigTypeEnum.SYSTEM.getType().equals(config.getType())) { |         if (ConfigTypeEnum.SYSTEM.getType().equals(config.getType())) { | ||||||
|             throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE); |             throw exception(ErrorCodeConstants.CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE); | ||||||
|         } |         } | ||||||
|         // 删除 |         // 删除 | ||||||
|         configMapper.deleteById(id); |         configMapper.deleteById(id); | ||||||
|         // 发送刷新消息 |  | ||||||
|         configProducer.sendConfigRefreshMessage(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -109,7 +100,7 @@ public class ConfigServiceImpl implements ConfigService { | |||||||
|         } |         } | ||||||
|         ConfigDO config = configMapper.selectById(id); |         ConfigDO config = configMapper.selectById(id); | ||||||
|         if (config == null) { |         if (config == null) { | ||||||
|             throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_NOT_EXISTS); |             throw exception(ErrorCodeConstants.CONFIG_NOT_EXISTS); | ||||||
|         } |         } | ||||||
|         return config; |         return config; | ||||||
|     } |     } | ||||||
| @@ -122,10 +113,10 @@ public class ConfigServiceImpl implements ConfigService { | |||||||
|         } |         } | ||||||
|         // 如果 id 为空,说明不用比较是否为相同 id 的参数配置 |         // 如果 id 为空,说明不用比较是否为相同 id 的参数配置 | ||||||
|         if (id == null) { |         if (id == null) { | ||||||
|             throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_KEY_DUPLICATE); |             throw exception(ErrorCodeConstants.CONFIG_KEY_DUPLICATE); | ||||||
|         } |         } | ||||||
|         if (!config.getId().equals(id)) { |         if (!config.getId().equals(id)) { | ||||||
|             throw ServiceExceptionUtil.exception(ErrorCodeConstants.CONFIG_KEY_DUPLICATE); |             throw exception(ErrorCodeConstants.CONFIG_KEY_DUPLICATE); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -96,7 +96,7 @@ yudao: | |||||||
|     version: ${yudao.info.version} |     version: ${yudao.info.version} | ||||||
|     base-package: ${yudao.info.base-package} |     base-package: ${yudao.info.base-package} | ||||||
|   captcha: |   captcha: | ||||||
|     enable: true # 验证码的开关,默认为 true;注意,优先读取数据库 infra_config 的 yudao.captcha.enable,所以请从数据库修改,可能需要重启项目 |     enable: true # 验证码的开关,默认为 true | ||||||
|   codegen: |   codegen: | ||||||
|     base-package: ${yudao.info.base-package} |     base-package: ${yudao.info.base-package} | ||||||
|     db-schemas: ${spring.datasource.dynamic.datasource.master.name} |     db-schemas: ${spring.datasource.dynamic.datasource.master.name} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV