diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java index 301828b6..a2110783 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java @@ -52,14 +52,15 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService { }); @Override + @SneakyThrows public List getTenantIds() { - return getTenantIdsCache.getUnchecked(Boolean.TRUE); + return getTenantIdsCache.get(Boolean.TRUE); } @Override @SneakyThrows public void validTenant(Long id) { - validTenantCache.getUnchecked(id).checkError(); + validTenantCache.get(id).checkError(); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java deleted file mode 100644 index 5bc008ac..00000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.system.mq.consumer.tenant; - -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage; -import cn.iocoder.yudao.module.system.service.tenant.TenantService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 针对 {@link cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage} 的消费者 - * - * @author 芋道源码 - */ -@Component -@Slf4j -public class TenantRefreshConsumer extends AbstractChannelMessageListener { - - @Resource - private TenantService tenantService; - - @Override - public void onMessage(TenantRefreshMessage message) { - log.info("[onMessage][收到 Tenant 刷新消息]"); - tenantService.initLocalCache(); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java deleted file mode 100644 index 19092a4b..00000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.system.mq.message.tenant; - -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 租户数据刷新 Message - * - * @author 芋道源码 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class TenantRefreshMessage extends AbstractChannelMessage { - - @Override - public String getChannel() { - return "system.tenant.refresh"; - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java deleted file mode 100644 index eaa9f658..00000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.system.mq.producer.tenant; - -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; -import cn.iocoder.yudao.module.system.mq.message.permission.RoleRefreshMessage; -import cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * Tenant 租户相关消息的 Producer - * - * @author 芋道源码 - */ -@Component -public class TenantProducer { - - @Resource - private RedisMQTemplate redisMQTemplate; - - /** - * 发送 {@link RoleRefreshMessage} 消息 - */ - public void sendTenantRefreshMessage() { - TenantRefreshMessage message = new TenantRefreshMessage(); - redisMQTemplate.send(message); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java index fde379e3..b56134e7 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java @@ -22,11 +22,6 @@ import java.util.Set; */ public interface TenantService { - /** - * 初始化租户的本地缓存 - */ - void initLocalCache(); - /** * 创建租户 * diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java index 160ffe82..dc4a67ef 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java @@ -23,31 +23,25 @@ import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; -import cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer; import cn.iocoder.yudao.module.system.service.permission.MenuService; import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.permission.RoleService; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; -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 java.util.*; +import java.util.List; +import java.util.Objects; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertImmutableMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static java.util.Collections.singleton; @@ -61,26 +55,6 @@ import static java.util.Collections.singleton; @Slf4j public class TenantServiceImpl implements TenantService { - /** - * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 - * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 - */ - private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; - - /** - * 角色缓存 - * key:角色编号 {@link RoleDO#getId()} - * - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 - */ - @Getter - private volatile Map tenantCache; - /** - * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新 - */ - @Getter - private volatile Date maxUpdateTime; - @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") @Autowired(required = false) // 由于 yudao.tenant.enable 配置项,可以关闭多租户的功能,所以这里只能不强制注入 private TenantProperties tenantProperties; @@ -100,61 +74,15 @@ public class TenantServiceImpl implements TenantService { @Resource private PermissionService permissionService; - @Resource - private TenantProducer tenantProducer; - - /** - * 初始化 {@link #tenantCache} 缓存 - */ - @Override - @PostConstruct - public void initLocalCache() { - // 获取租户列表,如果有更新 - List tenantList = loadTenantIfUpdate(maxUpdateTime); - if (CollUtil.isEmpty(tenantList)) { - return; - } - - // 写入缓存 - tenantCache = convertImmutableMap(tenantList, TenantDO::getId); - maxUpdateTime = getMaxValue(tenantList, TenantDO::getUpdateTime); - log.info("[initLocalCache][初始化 Tenant 数量为 {}]", tenantList.size()); - } - - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) - public void schedulePeriodicRefresh() { - initLocalCache(); - } - - /** - * 如果租户发生变化,从数据库中获取最新的全量租户。 - * 如果未发生变化,则返回空 - * - * @param maxUpdateTime 当前租户的最大更新时间 - * @return 租户列表 - */ - private List loadTenantIfUpdate(Date maxUpdateTime) { - // 第一步,判断是否要更新。 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 - log.info("[loadTenantIfUpdate][首次加载全量租户]"); - } else { // 判断数据库中是否有更新的租户 - if (tenantMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { - return null; - } - log.info("[loadTenantIfUpdate][增量加载全量租户]"); - } - // 第二步,如果有更新,则从数据库加载所有租户 - return tenantMapper.selectList(); - } - @Override public List getTenantIds() { - return new ArrayList<>(tenantCache.keySet()); + List tenants = tenantMapper.selectList(); + return CollectionUtils.convertList(tenants, TenantDO::getId); } @Override public void validTenant(Long id) { - TenantDO tenant = tenantCache.get(id); + TenantDO tenant = getTenant(id); if (tenant == null) { throw exception(TENANT_NOT_EXISTS); } @@ -184,13 +112,6 @@ public class TenantServiceImpl implements TenantService { // 修改租户的管理员 tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); }); - // 发送刷新消息 - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - @Override - public void afterCommit() { - tenantProducer.sendTenantRefreshMessage(); - } - }); return tenant.getId(); } @@ -228,13 +149,6 @@ public class TenantServiceImpl implements TenantService { if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds()); } - // 发送刷新消息 - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - @Override - public void afterCommit() { - tenantProducer.sendTenantRefreshMessage(); - } - }); } @Override diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java index 37ff97fd..61daa866 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.system.service.tenant; -import cn.hutool.core.util.ReflectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.tenant.config.TenantProperties; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; @@ -16,14 +16,12 @@ import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; -import cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer; import cn.iocoder.yudao.module.system.service.permission.MenuService; import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.permission.RoleService; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; @@ -34,13 +32,11 @@ import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; @@ -78,43 +74,18 @@ public class TenantServiceImplTest extends BaseDbUnitTest { private MenuService menuService; @MockBean private PermissionService permissionService; - @MockBean - private TenantProducer tenantProducer; @BeforeEach public void setUp() { - // 清理缓存 - ReflectUtil.setFieldValue(tenantService, "tenantCache", Collections.emptyMap()); - ReflectUtil.setFieldValue(tenantService, "maxUpdateTime", null); // 清理租户上下文 TenantContextHolder.clear(); } - @Test - public void testInitLocalCache() { - // mock 数据 - TenantDO tenantDO1 = randomPojo(TenantDO.class); - tenantMapper.insert(tenantDO1); - TenantDO tenantDO2 = randomPojo(TenantDO.class); - tenantMapper.insert(tenantDO2); - - // 调用 - tenantService.initLocalCache(); - // 断言 tenantCache 缓存 - Map tenantCache = tenantService.getTenantCache(); - assertEquals(2, tenantCache.size()); - assertPojoEquals(tenantDO1, tenantCache.get(tenantDO1.getId())); - assertPojoEquals(tenantDO2, tenantCache.get(tenantDO2.getId())); - // 断言 maxUpdateTime 缓存 - assertEquals(max(tenantDO1.getUpdateTime(), tenantDO2.getUpdateTime()), tenantService.getMaxUpdateTime()); - } - @Test public void testGetTenantIds() { // mock 数据 TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L)); tenantMapper.insert(tenant); - tenantService.initLocalCache(); // 调用,并断言业务异常 List result = tenantService.getTenantIds(); @@ -131,7 +102,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest { // mock 数据 TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.DISABLE.getStatus())); tenantMapper.insert(tenant); - tenantService.initLocalCache(); // 调用,并断言业务异常 assertServiceException(() -> tenantService.validTenant(1L), TENANT_DISABLE, tenant.getName()); @@ -143,7 +113,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest { TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus()) .setExpireTime(buildTime(2020, 2, 2))); tenantMapper.insert(tenant); - tenantService.initLocalCache(); // 调用,并断言业务异常 assertServiceException(() -> tenantService.validTenant(1L), TENANT_EXPIRE, tenant.getName()); @@ -155,7 +124,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest { TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus()) .setExpireTime(addTime(Duration.ofDays(1)))); tenantMapper.insert(tenant); - tenantService.initLocalCache(); // 调用,并断言业务异常 tenantService.validTenant(1L); @@ -206,8 +174,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest { verify(permissionService).assignRoleMenu(eq(200L), same(tenantPackage.getMenuIds())); // verify 分配角色 verify(permissionService).assignUserRole(eq(300L), eq(singleton(200L))); - // verify 发送刷新消息 - verify(tenantProducer).sendTenantRefreshMessage(); } @Test @@ -240,8 +206,6 @@ public class TenantServiceImplTest extends BaseDbUnitTest { // 校验是否更新正确 TenantDO tenant = tenantMapper.selectById(reqVO.getId()); // 获取最新的 assertPojoEquals(reqVO, tenant); - // verify 发送刷新消息 - verify(tenantProducer).sendTenantRefreshMessage(); // verify 设置角色权限 verify(permissionService).assignRoleMenu(eq(100L), eq(asSet(200L, 201L))); verify(permissionService).assignRoleMenu(eq(101L), eq(asSet(201L)));