From d67f4a7f46ce1f4a999916c001131df1b3fd9311 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Jul 2023 09:10:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E4=BB=B6=E9=85=8D=E7=BD=AE=E7=9A=84?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E7=BC=93=E5=AD=98=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20Job=20=E8=BD=AE=E8=AF=A2=EF=BC=8C=E6=9B=BF=E4=BB=A3=20MQ=20?= =?UTF-8?q?=E5=B9=BF=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/mysql/file/FileConfigMapper.java | 6 ++ .../file/FileConfigRefreshConsumer.java | 29 --------- .../infra/mq/consumer/package-info.java | 2 +- .../file/FileConfigRefreshMessage.java | 17 ----- .../module/infra/mq/message/package-info.java | 2 +- .../mq/producer/file/FileConfigProducer.java | 26 -------- .../infra/mq/producer/package-info.java | 2 +- .../infra/service/file/FileConfigService.java | 5 -- .../service/file/FileConfigServiceImpl.java | 64 +++++++++++++------ .../file/FileConfigServiceImplTest.java | 15 ++--- 10 files changed, 56 insertions(+), 112 deletions(-) delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java index a2bf16be4..3bec97e0b 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java @@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; @Mapper public interface FileConfigMapper extends BaseMapperX { @@ -18,4 +21,7 @@ public interface FileConfigMapper extends BaseMapperX { .orderByDesc(FileConfigDO::getId)); } + @Select("SELECT COUNT(*) FROM infra_file_config WHERE update_time > #{maxUpdateTime}") + Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime); + } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java deleted file mode 100644 index a3b41197f..000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.infra.mq.consumer.file; - -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage; -import cn.iocoder.yudao.module.infra.service.file.FileConfigService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 针对 {@link FileConfigRefreshMessage} 的消费者 - * - * @author 芋道源码 - */ -@Component -@Slf4j -public class FileConfigRefreshConsumer extends AbstractChannelMessageListener { - - @Resource - private FileConfigService fileConfigService; - - @Override - public void onMessage(FileConfigRefreshMessage message) { - log.info("[onMessage][收到 FileConfig 刷新消息]"); - fileConfigService.initLocalCache(); - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java index faba2d870..5ba526413 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java @@ -1,4 +1,4 @@ /** - * 占位符,避免缩进 + * 消息队列的消费者 */ package cn.iocoder.yudao.module.infra.mq.consumer; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java deleted file mode 100644 index 7cc120de3..000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.module.infra.mq.message.file; - -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; -import lombok.Data; - -/** - * 文件配置数据刷新 Message - */ -@Data -public class FileConfigRefreshMessage extends AbstractChannelMessage { - - @Override - public String getChannel() { - return "infra.file-config.refresh"; - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java index 380693339..19edb0241 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java @@ -1,4 +1,4 @@ /** - * 占位符,避免缩进 + * 消息队列的消息 */ package cn.iocoder.yudao.module.infra.mq.message; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java deleted file mode 100644 index a666b185d..000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.infra.mq.producer.file; - -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; -import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 文件配置相关消息的 Producer - */ -@Component -public class FileConfigProducer { - - @Resource - private RedisMQTemplate redisMQTemplate; - - /** - * 发送 {@link FileConfigRefreshMessage} 消息 - */ - public void sendFileConfigRefreshMessage() { - FileConfigRefreshMessage message = new FileConfigRefreshMessage(); - redisMQTemplate.send(message); - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java index f1f53a91c..343179cb8 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java @@ -1,4 +1,4 @@ /** - * 占位符,避免缩进 + * 消息队列的生产者 */ package cn.iocoder.yudao.module.infra.mq.producer; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java index 43ab5bc68..1b279391a 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java @@ -16,11 +16,6 @@ import javax.validation.Valid; */ public interface FileConfigService { - /** - * 初始化文件客户端 - */ - void initLocalCache(); - /** * 创建文件配置 * diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java index 6236df6ff..0d2476753 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.infra.service.file; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.file.core.client.FileClient; @@ -15,20 +17,20 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigU import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; -import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionSynchronization; -import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.validation.annotation.Validated; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.validation.Validator; +import java.time.LocalDateTime; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; @@ -46,6 +48,12 @@ public class FileConfigServiceImpl implements FileConfigService { @Resource private FileClientFactory fileClientFactory; + + /** + * 文件配置的缓存 + */ + @Getter + private List fileConfigCache; /** * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的 */ @@ -55,9 +63,6 @@ public class FileConfigServiceImpl implements FileConfigService { @Resource private FileConfigMapper fileConfigMapper; - @Resource - private FileConfigProducer fileConfigProducer; - @Resource private Validator validator; @@ -76,6 +81,27 @@ public class FileConfigServiceImpl implements FileConfigService { masterFileClient = fileClientFactory.getFileClient(config.getId()); } }); + this.fileConfigCache = configs; + } + + /** + * 通过定时任务轮询,刷新缓存 + * + * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新 + */ + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) + public void refreshLocalCache() { + // 情况一:如果缓存里没有数据,则直接刷新缓存 + if (CollUtil.isEmpty(fileConfigCache)) { + initLocalCache(); + return; + } + + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 + LocalDateTime maxTime = CollectionUtils.getMaxValue(fileConfigCache, FileConfigDO::getUpdateTime); + if (fileConfigMapper.selectCountByUpdateTimeGt(maxTime) > 0) { + initLocalCache(); + } } @Override @@ -85,9 +111,9 @@ public class FileConfigServiceImpl implements FileConfigService { .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) .setMaster(false); // 默认非 master fileConfigMapper.insert(fileConfig); - // 发送刷新配置的消息 - fileConfigProducer.sendFileConfigRefreshMessage(); - // 返回 + + // 刷新缓存 + initLocalCache(); return fileConfig.getId(); } @@ -99,8 +125,9 @@ public class FileConfigServiceImpl implements FileConfigService { FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO) .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); fileConfigMapper.updateById(updateObj); - // 发送刷新配置的消息 - fileConfigProducer.sendFileConfigRefreshMessage(); + + // 刷新缓存 + initLocalCache(); } @Override @@ -112,15 +139,9 @@ public class FileConfigServiceImpl implements FileConfigService { fileConfigMapper.updateBatch(new FileConfigDO().setMaster(false)); // 更新 fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true)); - // 发送刷新配置的消息 - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - @Override - public void afterCommit() { - fileConfigProducer.sendFileConfigRefreshMessage(); - } - - }); + // 刷新缓存 + initLocalCache(); } private FileClientConfig parseClientConfig(Integer storage, Map config) { @@ -143,8 +164,9 @@ public class FileConfigServiceImpl implements FileConfigService { } // 删除 fileConfigMapper.deleteById(id); - // 发送刷新配置的消息 - fileConfigProducer.sendFileConfigRefreshMessage(); + + // 刷新缓存 + initLocalCache(); } private FileConfigDO validateFileConfigExists(Long id) { diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java index 656955194..079054864 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigP import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; -import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; import lombok.Data; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; @@ -55,8 +54,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @Resource private FileConfigMapper fileConfigMapper; - @MockBean - private FileConfigProducer fileConfigProducer; @MockBean private Validator validator; @MockBean @@ -81,6 +78,10 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { verify(fileClientFactory).createOrUpdateFileClient(eq(2L), eq(configDO2.getStorage()), eq(configDO2.getConfig())); assertSame(masterFileClient, fileConfigService.getMasterFileClient()); + // 断言 fileConfigCache 缓存 + assertEquals(2, fileConfigService.getFileConfigCache().size()); + assertEquals(configDO1, fileConfigService.getFileConfigCache().get(0)); + assertEquals(configDO2, fileConfigService.getFileConfigCache().get(1)); } @Test @@ -101,8 +102,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { assertFalse(fileConfig.getMaster()); assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); - // verify 调用 - verify(fileConfigProducer).sendFileConfigRefreshMessage(); } @Test @@ -126,8 +125,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { assertPojoEquals(reqVO, fileConfig, "config"); assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); - // verify 调用 - verify(fileConfigProducer).sendFileConfigRefreshMessage(); } @Test @@ -152,8 +149,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { // 断言数据 assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster()); assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster()); - // verify 调用 - verify(fileConfigProducer).sendFileConfigRefreshMessage(); } @Test @@ -174,8 +169,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { fileConfigService.deleteFileConfig(id); // 校验数据不存在了 assertNull(fileConfigMapper.selectById(id)); - // verify 调用 - verify(fileConfigProducer).sendFileConfigRefreshMessage(); } @Test