Commit 3443aa6f5f28577087c74e24812698cd802dd507

Authored by YunaiV
1 parent 2706463e

优化本地缓存的刷新实现,数据变更时,强制刷新

Showing 18 changed files with 288 additions and 341 deletions
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java
1 package cn.iocoder.yudao.framework.tenant.core.aop; 1 package cn.iocoder.yudao.framework.tenant.core.aop;
2 2
3 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; 3 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
  4 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
4 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
5 import org.aspectj.lang.ProceedingJoinPoint; 6 import org.aspectj.lang.ProceedingJoinPoint;
6 import org.aspectj.lang.annotation.Around; 7 import org.aspectj.lang.annotation.Around;
@@ -11,6 +12,8 @@ import org.aspectj.lang.annotation.Aspect; @@ -11,6 +12,8 @@ import org.aspectj.lang.annotation.Aspect;
11 * 例如说,一个定时任务,读取所有数据,进行处理。 12 * 例如说,一个定时任务,读取所有数据,进行处理。
12 * 又例如说,读取所有数据,进行缓存。 13 * 又例如说,读取所有数据,进行缓存。
13 * 14 *
  15 + * 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致
  16 + *
14 * @author 芋道源码 17 * @author 芋道源码
15 */ 18 */
16 @Aspect 19 @Aspect
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
@@ -37,6 +37,22 @@ public class TenantUtils { @@ -37,6 +37,22 @@ public class TenantUtils {
37 } 37 }
38 38
39 /** 39 /**
  40 + * 忽略租户,执行对应的逻辑
  41 + *
  42 + * @param runnable 逻辑
  43 + */
  44 + public static void executeIgnore(Runnable runnable) {
  45 + Boolean oldIgnore = TenantContextHolder.isIgnore();
  46 + try {
  47 + TenantContextHolder.setIgnore(true);
  48 + // 执行逻辑
  49 + runnable.run();
  50 + } finally {
  51 + TenantContextHolder.setIgnore(oldIgnore);
  52 + }
  53 + }
  54 +
  55 + /**
40 * 将多租户编号,添加到 header 中 56 * 将多租户编号,添加到 header 中
41 * 57 *
42 * @param headers HTTP 请求 headers 58 * @param headers HTTP 请求 headers
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
1 package cn.iocoder.yudao.module.infra.service.file; 1 package cn.iocoder.yudao.module.infra.service.file;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.hutool.core.io.resource.ResourceUtil; 3 import cn.hutool.core.io.resource.ResourceUtil;
5 import cn.hutool.core.util.IdUtil; 4 import cn.hutool.core.util.IdUtil;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; @@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
20 import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; 19 import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;
21 import lombok.Getter; 20 import lombok.Getter;
22 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
23 -import org.springframework.context.annotation.Lazy;  
24 import org.springframework.scheduling.annotation.Scheduled; 22 import org.springframework.scheduling.annotation.Scheduled;
25 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
26 import org.springframework.transaction.annotation.Transactional; 24 import org.springframework.transaction.annotation.Transactional;
@@ -79,20 +77,36 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -79,20 +77,36 @@ public class FileConfigServiceImpl implements FileConfigService {
79 @Resource 77 @Resource
80 private Validator validator; 78 private Validator validator;
81 79
82 - @Resource  
83 - @Lazy // 注入自己,所以延迟加载  
84 - private FileConfigService self;  
85 -  
86 @Override 80 @Override
87 @PostConstruct 81 @PostConstruct
88 public void initFileClients() { 82 public void initFileClients() {
89 - // 获取文件配置,如果有更新  
90 - List<FileConfigDO> configs = loadFileConfigIfUpdate(maxUpdateTime);  
91 - if (CollUtil.isEmpty(configs)) { 83 + initLocalCacheIfUpdate(null);
  84 + }
  85 +
  86 + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
  87 + public void schedulePeriodicRefresh() {
  88 + initLocalCacheIfUpdate(this.maxUpdateTime);
  89 + }
  90 +
  91 + /**
  92 + * 刷新本地缓存
  93 + *
  94 + * @param maxUpdateTime 最大更新时间
  95 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  96 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
  97 + */
  98 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  99 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  100 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  101 + if (maxUpdateTime != null
  102 + && fileConfigMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  103 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
92 return; 104 return;
93 } 105 }
  106 + List<FileConfigDO> configs = fileConfigMapper.selectList();
  107 + log.info("[initLocalCacheIfUpdate][缓存文件配置,数量为:{}]", configs.size());
94 108
95 - // 创建或更新支付 Client 109 + // 第二步:构建缓存。创建或更新文件 Client
96 configs.forEach(config -> { 110 configs.forEach(config -> {
97 fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); 111 fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
98 // 如果是 master,进行设置 112 // 如果是 master,进行设置
@@ -101,35 +115,8 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -101,35 +115,8 @@ public class FileConfigServiceImpl implements FileConfigService {
101 } 115 }
102 }); 116 });
103 117
104 - // 写入缓存  
105 - maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime);  
106 - log.info("[initFileClients][初始化 FileConfig 数量为 {}]", configs.size());  
107 - }  
108 -  
109 - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)  
110 - public void schedulePeriodicRefresh() {  
111 - self.initFileClients();  
112 - }  
113 -  
114 - /**  
115 - * 如果文件配置发生变化,从数据库中获取最新的全量文件配置。  
116 - * 如果未发生变化,则返回空  
117 - *  
118 - * @param maxUpdateTime 当前文件配置的最大更新时间  
119 - * @return 文件配置列表  
120 - */  
121 - private List<FileConfigDO> loadFileConfigIfUpdate(LocalDateTime maxUpdateTime) {  
122 - // 第一步,判断是否要更新。  
123 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
124 - log.info("[loadFileConfigIfUpdate][首次加载全量文件配置]");  
125 - } else { // 判断数据库中是否有更新的文件配置  
126 - if (fileConfigMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
127 - return null;  
128 - }  
129 - log.info("[loadFileConfigIfUpdate][增量加载全量文件配置]");  
130 - }  
131 - // 第二步,如果有更新,则从数据库加载所有文件配置  
132 - return fileConfigMapper.selectList(); 118 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  119 + this.maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime);
133 } 120 }
134 121
135 @Override 122 @Override
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelService.java
@@ -22,7 +22,7 @@ public interface PayChannelService { @@ -22,7 +22,7 @@ public interface PayChannelService {
22 /** 22 /**
23 * 初始化支付客户端 23 * 初始化支付客户端
24 */ 24 */
25 - void initPayClients(); 25 + void initLocalCache();
26 26
27 /** 27 /**
28 * 创建支付渠道 28 * 创建支付渠道
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceImpl.java
1 package cn.iocoder.yudao.module.pay.service.merchant; 1 package cn.iocoder.yudao.module.pay.service.merchant;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.json.JSONUtil; 4 import cn.hutool.json.JSONUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -10,7 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -10,7 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
10 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; 9 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
11 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 10 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
12 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; 11 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
13 -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 12 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
14 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelCreateReqVO; 13 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelCreateReqVO;
15 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelExportReqVO; 14 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelExportReqVO;
16 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelPageReqVO; 15 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelPageReqVO;
@@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO; @@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO;
20 import cn.iocoder.yudao.module.pay.dal.mysql.merchant.PayChannelMapper; 19 import cn.iocoder.yudao.module.pay.dal.mysql.merchant.PayChannelMapper;
21 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; 20 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
22 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
23 -import org.springframework.context.annotation.Lazy;  
24 import org.springframework.scheduling.annotation.Scheduled; 22 import org.springframework.scheduling.annotation.Scheduled;
25 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
26 import org.springframework.validation.annotation.Validated; 24 import org.springframework.validation.annotation.Validated;
@@ -66,53 +64,47 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -66,53 +64,47 @@ public class PayChannelServiceImpl implements PayChannelService {
66 @Resource 64 @Resource
67 private Validator validator; 65 private Validator validator;
68 66
69 - @Resource  
70 - @Lazy // 注入自己,所以延迟加载  
71 - private PayChannelService self;  
72 - 67 + /**
  68 + * 初始化 {@link #payClientFactory} 缓存
  69 + */
73 @Override 70 @Override
74 @PostConstruct 71 @PostConstruct
75 - @TenantIgnore // 忽略自动化租户,全局初始化本地缓存  
76 - public void initPayClients() {  
77 - // 获取支付渠道,如果有更新  
78 - List<PayChannelDO> payChannels = loadPayChannelIfUpdate(maxUpdateTime);  
79 - if (CollUtil.isEmpty(payChannels)) {  
80 - return;  
81 - }  
82 -  
83 - // 创建或更新支付 Client  
84 - payChannels.forEach(payChannel -> payClientFactory.createOrUpdatePayClient(payChannel.getId(),  
85 - payChannel.getCode(), payChannel.getConfig()));  
86 -  
87 - // 写入缓存  
88 - maxUpdateTime = CollectionUtils.getMaxValue(payChannels, PayChannelDO::getUpdateTime);  
89 - log.info("[initPayClients][初始化 PayChannel 数量为 {}]", payChannels.size()); 72 + public void initLocalCache() {
  73 + initLocalCacheIfUpdate(null);
90 } 74 }
91 75
92 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) 76 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
93 public void schedulePeriodicRefresh() { 77 public void schedulePeriodicRefresh() {
94 - self.initPayClients(); 78 + initLocalCacheIfUpdate(this.maxUpdateTime);
95 } 79 }
96 80
97 /** 81 /**
98 - * 如果支付渠道发生变化,从数据库中获取最新的全量支付渠道。  
99 - * 如果未发生变化,则返回空 82 + * 刷新本地缓存
100 * 83 *
101 - * @param maxUpdateTime 当前支付渠道的最大更新时间  
102 - * @return 支付渠道列表 84 + * @param maxUpdateTime 最大更新时间
  85 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  86 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
103 */ 87 */
104 - private List<PayChannelDO> loadPayChannelIfUpdate(LocalDateTime maxUpdateTime) {  
105 - // 第一步,判断是否要更新。  
106 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
107 - log.info("[loadPayChannelIfUpdate][首次加载全量支付渠道]");  
108 - } else { // 判断数据库中是否有更新的支付渠道  
109 - if (channelMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
110 - return null; 88 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  89 + // 注意:忽略自动多租户,因为要全局初始化缓存
  90 + TenantUtils.executeIgnore(() -> {
  91 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  92 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  93 + if (maxUpdateTime != null
  94 + && channelMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  95 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  96 + return;
111 } 97 }
112 - log.info("[loadPayChannelIfUpdate][增量加载全量支付渠道]");  
113 - }  
114 - // 第二步,如果有更新,则从数据库加载所有支付渠道  
115 - return channelMapper.selectList(); 98 + List<PayChannelDO> channels = channelMapper.selectList();
  99 + log.info("[initLocalCacheIfUpdate][缓存支付渠道,数量为:{}]", channels.size());
  100 +
  101 + // 第二步:构建缓存。创建或更新支付 Client
  102 + channels.forEach(payChannel -> payClientFactory.createOrUpdatePayClient(payChannel.getId(),
  103 + payChannel.getCode(), payChannel.getConfig()));
  104 +
  105 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  106 + this.maxUpdateTime = CollectionUtils.getMaxValue(channels, PayChannelDO::getUpdateTime);
  107 + });
116 } 108 }
117 109
118 @Override 110 @Override
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceTest.java
@@ -49,7 +49,6 @@ public class PayChannelServiceTest extends BaseDbUnitTest { @@ -49,7 +49,6 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
49 @Test 49 @Test
50 public void testCreateWechatVersion2Channel_success() { 50 public void testCreateWechatVersion2Channel_success() {
51 // 准备参数 51 // 准备参数
52 -  
53 WXPayClientConfig v2Config = getV2Config(); 52 WXPayClientConfig v2Config = getV2Config();
54 PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { 53 PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> {
55 o.setCode(PayChannelEnum.WX_PUB.getCode()); 54 o.setCode(PayChannelEnum.WX_PUB.getCode());
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql
@@ -43,6 +43,7 @@ CREATE TABLE IF NOT EXISTS &quot;pay_channel&quot; ( @@ -43,6 +43,7 @@ CREATE TABLE IF NOT EXISTS &quot;pay_channel&quot; (
43 "updater" varchar(64) NULL DEFAULT '', 43 "updater" varchar(64) NULL DEFAULT '',
44 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 44 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
45 "deleted" bit(1) NOT NULL DEFAULT FALSE, 45 "deleted" bit(1) NOT NULL DEFAULT FALSE,
  46 + "tenant_id" bigint not null default '0',
46 PRIMARY KEY ("id") 47 PRIMARY KEY ("id")
47 ) COMMENT = '支付渠道'; 48 ) COMMENT = '支付渠道';
48 49
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsChannelRefreshConsumer.java
@@ -23,7 +23,7 @@ public class SmsChannelRefreshConsumer extends AbstractChannelMessageListener&lt;Sm @@ -23,7 +23,7 @@ public class SmsChannelRefreshConsumer extends AbstractChannelMessageListener&lt;Sm
23 @Override 23 @Override
24 public void onMessage(SmsChannelRefreshMessage message) { 24 public void onMessage(SmsChannelRefreshMessage message) {
25 log.info("[onMessage][收到 SmsChannel 刷新消息]"); 25 log.info("[onMessage][收到 SmsChannel 刷新消息]");
26 - smsChannelService.initSmsClients(); 26 + smsChannelService.initLocalCache();
27 } 27 }
28 28
29 } 29 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
@@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil; @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 7 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
8 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO;
9 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; 9 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
10 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; 10 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO;
@@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap; @@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap;
17 import com.google.common.collect.ImmutableMultimap; 17 import com.google.common.collect.ImmutableMultimap;
18 import com.google.common.collect.Multimap; 18 import com.google.common.collect.Multimap;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 -import org.springframework.context.annotation.Lazy;  
21 import org.springframework.scheduling.annotation.Scheduled; 20 import org.springframework.scheduling.annotation.Scheduled;
22 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
23 import org.springframework.validation.annotation.Validated; 22 import org.springframework.validation.annotation.Validated;
@@ -73,58 +72,55 @@ public class DeptServiceImpl implements DeptService { @@ -73,58 +72,55 @@ public class DeptServiceImpl implements DeptService {
73 @Resource 72 @Resource
74 private DeptProducer deptProducer; 73 private DeptProducer deptProducer;
75 74
76 - @Resource  
77 - @Lazy // 注入自己,所以延迟加载  
78 - private DeptService self;  
79 - 75 + /**
  76 + * 初始化 {@link #parentDeptCache} 和 {@link #deptCache} 缓存
  77 + */
80 @Override 78 @Override
81 @PostConstruct 79 @PostConstruct
82 - @TenantIgnore // 初始化缓存,无需租户过滤  
83 public synchronized void initLocalCache() { 80 public synchronized void initLocalCache() {
84 - // 获取部门列表,如果有更新  
85 - List<DeptDO> deptList = loadDeptIfUpdate(maxUpdateTime);  
86 - if (CollUtil.isEmpty(deptList)) {  
87 - return;  
88 - }  
89 -  
90 - // 构建缓存  
91 - ImmutableMap.Builder<Long, DeptDO> builder = ImmutableMap.builder();  
92 - ImmutableMultimap.Builder<Long, DeptDO> parentBuilder = ImmutableMultimap.builder();  
93 - deptList.forEach(sysRoleDO -> {  
94 - builder.put(sysRoleDO.getId(), sysRoleDO);  
95 - parentBuilder.put(sysRoleDO.getParentId(), sysRoleDO);  
96 - });  
97 - // 设置缓存  
98 - deptCache = builder.build();  
99 - parentDeptCache = parentBuilder.build();  
100 - maxUpdateTime = CollectionUtils.getMaxValue(deptList, DeptDO::getUpdateTime);  
101 - log.info("[initLocalCache][初始化 Dept 数量为 {}]", deptList.size()); 81 + initLocalCacheIfUpdate(null);
102 } 82 }
103 83
104 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) 84 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
105 public void schedulePeriodicRefresh() { 85 public void schedulePeriodicRefresh() {
106 - self.initLocalCache(); 86 + initLocalCacheIfUpdate(this.maxUpdateTime);
107 } 87 }
108 88
109 /** 89 /**
110 - * 如果部门发生变化,从数据库中获取最新的全量部门。  
111 - * 如果未发生变化,则返回空 90 + * 刷新本地缓存
112 * 91 *
113 - * @param maxUpdateTime 当前部门的最大更新时间  
114 - * @return 部门列表 92 + * @param maxUpdateTime 最大更新时间
  93 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  94 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
115 */ 95 */
116 - protected List<DeptDO> loadDeptIfUpdate(LocalDateTime maxUpdateTime) {  
117 - // 第一步,判断是否要更新。  
118 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
119 - log.info("[loadDeptIfUpdate][首次加载全量部门]");  
120 - } else { // 判断数据库中是否有更新的部门  
121 - if (deptMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
122 - return null; 96 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  97 + // 注意:忽略自动多租户,因为要全局初始化缓存
  98 + TenantUtils.executeIgnore(() -> {
  99 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  100 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  101 + if (maxUpdateTime != null
  102 + && deptMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  103 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  104 + return;
123 } 105 }
124 - log.info("[loadDeptIfUpdate][增量加载全量部门]");  
125 - }  
126 - // 第二步,如果有更新,则从数据库加载所有部门  
127 - return deptMapper.selectList(); 106 + List<DeptDO> depts = deptMapper.selectList();
  107 + log.info("[initLocalCacheIfUpdate][缓存部门,数量为:{}]", depts.size());
  108 +
  109 + // 第二步:构建缓存。创建或更新支付 Client
  110 + // 构建缓存
  111 + ImmutableMap.Builder<Long, DeptDO> builder = ImmutableMap.builder();
  112 + ImmutableMultimap.Builder<Long, DeptDO> parentBuilder = ImmutableMultimap.builder();
  113 + depts.forEach(sysRoleDO -> {
  114 + builder.put(sysRoleDO.getId(), sysRoleDO);
  115 + parentBuilder.put(sysRoleDO.getParentId(), sysRoleDO);
  116 + });
  117 + // 设置缓存
  118 + deptCache = builder.build();
  119 + parentDeptCache = parentBuilder.build();
  120 +
  121 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  122 + this.maxUpdateTime = CollectionUtils.getMaxValue(depts, DeptDO::getUpdateTime);
  123 + });
128 } 124 }
129 125
130 @Override 126 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java
@@ -24,7 +24,9 @@ import org.springframework.validation.annotation.Validated; @@ -24,7 +24,9 @@ import org.springframework.validation.annotation.Validated;
24 import javax.annotation.PostConstruct; 24 import javax.annotation.PostConstruct;
25 import javax.annotation.Resource; 25 import javax.annotation.Resource;
26 import java.time.LocalDateTime; 26 import java.time.LocalDateTime;
27 -import java.util.*; 27 +import java.util.Collection;
  28 +import java.util.List;
  29 +import java.util.Map;
28 30
29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 32 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
@@ -74,42 +76,37 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService { @@ -74,42 +76,37 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
74 @Override 76 @Override
75 @PostConstruct 77 @PostConstruct
76 public void initLocalCache() { 78 public void initLocalCache() {
77 - // 获取客户端列表,如果有更新  
78 - List<OAuth2ClientDO> tenantList = loadOAuth2ClientIfUpdate(maxUpdateTime);  
79 - if (CollUtil.isEmpty(tenantList)) {  
80 - return;  
81 - }  
82 -  
83 - // 写入缓存  
84 - clientCache = convertMap(tenantList, OAuth2ClientDO::getClientId);  
85 - maxUpdateTime = getMaxValue(tenantList, OAuth2ClientDO::getUpdateTime);  
86 - log.info("[initLocalCache][初始化 OAuth2Client 数量为 {}]", tenantList.size()); 79 + initLocalCacheIfUpdate(null);
87 } 80 }
88 81
89 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) 82 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
90 public void schedulePeriodicRefresh() { 83 public void schedulePeriodicRefresh() {
91 - initLocalCache(); 84 + initLocalCacheIfUpdate(this.maxUpdateTime);
92 } 85 }
93 86
94 /** 87 /**
95 - * 如果客户端发生变化,从数据库中获取最新的全量客户端。  
96 - * 如果未发生变化,则返回空 88 + * 刷新本地缓存
97 * 89 *
98 - * @param maxUpdateTime 当前客户端的最大更新时间  
99 - * @return 客户端列表 90 + * @param maxUpdateTime 最大更新时间
  91 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  92 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
100 */ 93 */
101 - private List<OAuth2ClientDO> loadOAuth2ClientIfUpdate(LocalDateTime maxUpdateTime) {  
102 - // 第一步,判断是否要更新。  
103 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
104 - log.info("[loadOAuth2ClientIfUpdate][首次加载全量客户端]");  
105 - } else { // 判断数据库中是否有更新的客户端  
106 - if (oauth2ClientMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
107 - return null;  
108 - }  
109 - log.info("[loadOAuth2ClientIfUpdate][增量加载全量客户端]"); 94 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  95 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  96 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  97 + if (maxUpdateTime != null
  98 + && oauth2ClientMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  99 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  100 + return;
110 } 101 }
111 - // 第二步,如果有更新,则从数据库加载所有客户端  
112 - return oauth2ClientMapper.selectList(); 102 + List<OAuth2ClientDO> clients = oauth2ClientMapper.selectList();
  103 + log.info("[initLocalCacheIfUpdate][缓存 OAuth2 客户端,数量为:{}]", clients.size());
  104 +
  105 + // 第二步:构建缓存。
  106 + clientCache = convertMap(clients, OAuth2ClientDO::getClientId);
  107 +
  108 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  109 + this.maxUpdateTime = getMaxValue(clients, OAuth2ClientDO::getUpdateTime);
113 } 110 }
114 111
115 @Override 112 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java
@@ -102,6 +102,7 @@ public class MenuServiceImpl implements MenuService { @@ -102,6 +102,7 @@ public class MenuServiceImpl implements MenuService {
102 * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存 102 * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
103 */ 103 */
104 private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) { 104 private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  105 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
105 // 如果没有增量的数据变化,则不进行本地缓存的刷新 106 // 如果没有增量的数据变化,则不进行本地缓存的刷新
106 if (maxUpdateTime != null 107 if (maxUpdateTime != null
107 && menuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { 108 && menuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
@@ -111,7 +112,7 @@ public class MenuServiceImpl implements MenuService { @@ -111,7 +112,7 @@ public class MenuServiceImpl implements MenuService {
111 List<MenuDO> menuList = menuMapper.selectList(); 112 List<MenuDO> menuList = menuMapper.selectList();
112 log.info("[initLocalCacheIfUpdate][缓存菜单,数量为:{}]", menuList.size()); 113 log.info("[initLocalCacheIfUpdate][缓存菜单,数量为:{}]", menuList.size());
113 114
114 - // 构建缓存 115 + // 第二步:构建缓存。
115 ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder(); 116 ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder();
116 ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); 117 ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder();
117 menuList.forEach(menuDO -> { 118 menuList.forEach(menuDO -> {
@@ -123,7 +124,7 @@ public class MenuServiceImpl implements MenuService { @@ -123,7 +124,7 @@ public class MenuServiceImpl implements MenuService {
123 menuCache = menuCacheBuilder.build(); 124 menuCache = menuCacheBuilder.build();
124 permissionMenuCache = permMenuCacheBuilder.build(); 125 permissionMenuCache = permMenuCacheBuilder.build();
125 126
126 - // 设置最新的 maxUpdateTime,用于下次的增量判断 127 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
127 this.maxUpdateTime = CollectionUtils.getMaxValue(menuList, MenuDO::getUpdateTime); 128 this.maxUpdateTime = CollectionUtils.getMaxValue(menuList, MenuDO::getUpdateTime);
128 } 129 }
129 130
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils; @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
9 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 9 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
10 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; 10 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
11 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 11 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
  12 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
12 import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; 13 import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
13 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; 14 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
14 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; 15 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@@ -31,7 +32,6 @@ import com.google.common.collect.Sets; @@ -31,7 +32,6 @@ import com.google.common.collect.Sets;
31 import lombok.Getter; 32 import lombok.Getter;
32 import lombok.Setter; 33 import lombok.Setter;
33 import lombok.extern.slf4j.Slf4j; 34 import lombok.extern.slf4j.Slf4j;
34 -import org.springframework.context.annotation.Lazy;  
35 import org.springframework.scheduling.annotation.Scheduled; 35 import org.springframework.scheduling.annotation.Scheduled;
36 import org.springframework.stereotype.Service; 36 import org.springframework.stereotype.Service;
37 import org.springframework.transaction.annotation.Transactional; 37 import org.springframework.transaction.annotation.Transactional;
@@ -126,106 +126,84 @@ public class PermissionServiceImpl implements PermissionService { @@ -126,106 +126,84 @@ public class PermissionServiceImpl implements PermissionService {
126 @Resource 126 @Resource
127 private PermissionProducer permissionProducer; 127 private PermissionProducer permissionProducer;
128 128
129 - @Resource  
130 - @Lazy // 注入自己,所以延迟加载  
131 - private PermissionService self;  
132 -  
133 @Override 129 @Override
134 @PostConstruct 130 @PostConstruct
135 - @TenantIgnore // 初始化缓存,无需租户过滤  
136 public void initLocalCache() { 131 public void initLocalCache() {
137 - initUserRoleLocalCache();  
138 - initRoleMenuLocalCache();  
139 - }  
140 -  
141 - /**  
142 - * 初始化 {@link #roleMenuCache} 和 {@link #menuRoleCache} 缓存  
143 - */  
144 - @VisibleForTesting  
145 - void initRoleMenuLocalCache() {  
146 - // 获取角色与菜单的关联列表,如果有更新  
147 - List<RoleMenuDO> roleMenuList = loadRoleMenuIfUpdate(roleMenuMaxUpdateTime);  
148 - if (CollUtil.isEmpty(roleMenuList)) {  
149 - return;  
150 - }  
151 -  
152 - // 初始化 roleMenuCache 和 menuRoleCache 缓存  
153 - ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder();  
154 - ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder();  
155 - roleMenuList.forEach(roleMenuDO -> {  
156 - roleMenuCacheBuilder.put(roleMenuDO.getRoleId(), roleMenuDO.getMenuId());  
157 - menuRoleCacheBuilder.put(roleMenuDO.getMenuId(), roleMenuDO.getRoleId());  
158 - });  
159 - roleMenuCache = roleMenuCacheBuilder.build();  
160 - menuRoleCache = menuRoleCacheBuilder.build();  
161 - roleMenuMaxUpdateTime = getMaxValue(roleMenuList, RoleMenuDO::getUpdateTime);  
162 - log.info("[initRoleMenuLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size());  
163 - }  
164 -  
165 - /**  
166 - * 初始化 {@link #userRoleCache} 缓存  
167 - */  
168 - @VisibleForTesting  
169 - void initUserRoleLocalCache() {  
170 - // 获取用户与角色的关联列表,如果有更新  
171 - List<UserRoleDO> userRoleList = loadUserRoleIfUpdate(userRoleMaxUpdateTime);  
172 - if (CollUtil.isEmpty(userRoleList)) {  
173 - return;  
174 - }  
175 -  
176 - // 初始化 userRoleCache 缓存  
177 - ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder();  
178 - userRoleList.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId()));  
179 - userRoleCache = CollectionUtils.convertMultiMap2(userRoleList, UserRoleDO::getUserId, UserRoleDO::getRoleId);  
180 - userRoleMaxUpdateTime = getMaxValue(userRoleList, UserRoleDO::getUpdateTime);  
181 - log.info("[initUserRoleLocalCache][初始化用户与角色的关联数量为 {}]", userRoleList.size()); 132 + initLocalCacheIfUpdateForRoleMenu(null);
  133 + initLocalCacheIfUpdateForUserRole(null);
182 } 134 }
183 135
184 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) 136 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
185 public void schedulePeriodicRefresh() { 137 public void schedulePeriodicRefresh() {
186 - self.initLocalCache(); 138 + initLocalCacheIfUpdateForRoleMenu(this.roleMenuMaxUpdateTime);
  139 + initLocalCacheIfUpdateForUserRole(this.userRoleMaxUpdateTime);
187 } 140 }
188 141
189 /** 142 /**
190 - * 如果角色与菜单的关联发生变化,从数据库中获取最新的全量角色与菜单的关联。  
191 - * 如果未发生变化,则返回空 143 + * 刷新 RoleMenu 本地缓存
192 * 144 *
193 - * @param maxUpdateTime 当前角色与菜单的关联的最大更新时间  
194 - * @return 角色与菜单的关联列表 145 + * @param maxUpdateTime 最大更新时间
  146 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  147 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
195 */ 148 */
196 - protected List<RoleMenuDO> loadRoleMenuIfUpdate(LocalDateTime maxUpdateTime) {  
197 - // 第一步,判断是否要更新。  
198 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
199 - log.info("[loadRoleMenuIfUpdate][首次加载全量角色与菜单的关联]");  
200 - } else { // 判断数据库中是否有更新的角色与菜单的关联  
201 - if (roleMenuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
202 - return null; 149 + @VisibleForTesting
  150 + void initLocalCacheIfUpdateForRoleMenu(LocalDateTime maxUpdateTime) {
  151 + // 注意:忽略自动多租户,因为要全局初始化缓存
  152 + TenantUtils.executeIgnore(() -> {
  153 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  154 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  155 + if (maxUpdateTime != null
  156 + && roleMenuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  157 + log.info("[initLocalCacheIfUpdateForRoleMenu][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  158 + return;
203 } 159 }
204 - log.info("[loadRoleMenuIfUpdate][增量加载全量角色与菜单的关联]");  
205 - }  
206 - // 第二步,如果有更新,则从数据库加载所有角色与菜单的关联  
207 - return roleMenuMapper.selectList(); 160 + List<RoleMenuDO> roleMenus = roleMenuMapper.selectList();
  161 + log.info("[initLocalCacheIfUpdateForRoleMenu][缓存角色与菜单,数量为:{}]", roleMenus.size());
  162 +
  163 + // 第二步:构建缓存。
  164 + ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder();
  165 + ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder();
  166 + roleMenus.forEach(roleMenuDO -> {
  167 + roleMenuCacheBuilder.put(roleMenuDO.getRoleId(), roleMenuDO.getMenuId());
  168 + menuRoleCacheBuilder.put(roleMenuDO.getMenuId(), roleMenuDO.getRoleId());
  169 + });
  170 + roleMenuCache = roleMenuCacheBuilder.build();
  171 + menuRoleCache = menuRoleCacheBuilder.build();
  172 +
  173 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  174 + this.roleMenuMaxUpdateTime = getMaxValue(roleMenus, RoleMenuDO::getUpdateTime);
  175 + });
208 } 176 }
209 177
210 /** 178 /**
211 - * 如果用户与角色的关联发生变化,从数据库中获取最新的全量用户与角色的关联。  
212 - * 如果未发生变化,则返回空 179 + * 刷新 UserRole 本地缓存
213 * 180 *
214 - * @param maxUpdateTime 当前角色与菜单的关联的最大更新时间  
215 - * @return 角色与菜单的关联列表 181 + * @param maxUpdateTime 最大更新时间
  182 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  183 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
216 */ 184 */
217 - protected List<UserRoleDO> loadUserRoleIfUpdate(LocalDateTime maxUpdateTime) {  
218 - // 第一步,判断是否要更新。  
219 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
220 - log.info("[loadUserRoleIfUpdate][首次加载全量用户与角色的关联]");  
221 - } else { // 判断数据库中是否有更新的用户与角色的关联  
222 - if (userRoleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
223 - return null; 185 + @VisibleForTesting
  186 + void initLocalCacheIfUpdateForUserRole(LocalDateTime maxUpdateTime) {
  187 + // 注意:忽略自动多租户,因为要全局初始化缓存
  188 + TenantUtils.executeIgnore(() -> {
  189 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  190 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  191 + if (maxUpdateTime != null
  192 + && userRoleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  193 + log.info("[initLocalCacheIfUpdateForUserRole][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  194 + return;
224 } 195 }
225 - log.info("[loadUserRoleIfUpdate][增量加载全量用户与角色的关联]");  
226 - }  
227 - // 第二步,如果有更新,则从数据库加载所有用户与角色的关联  
228 - return userRoleMapper.selectList(); 196 + List<UserRoleDO> userRoles = userRoleMapper.selectList();
  197 + log.info("[initLocalCacheIfUpdateForUserRole][缓存用户与角色,数量为:{}]", userRoles.size());
  198 +
  199 + // 第二步:构建缓存。
  200 + ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder();
  201 + userRoles.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId()));
  202 + userRoleCache = CollectionUtils.convertMultiMap2(userRoles, UserRoleDO::getUserId, UserRoleDO::getRoleId);
  203 +
  204 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  205 + this.userRoleMaxUpdateTime = getMaxValue(userRoles, UserRoleDO::getUpdateTime);
  206 + });
229 } 207 }
230 208
231 @Override 209 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
@@ -6,8 +6,7 @@ import cn.hutool.core.util.ObjectUtil; @@ -6,8 +6,7 @@ import cn.hutool.core.util.ObjectUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9 -import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;  
10 -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 9 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; 10 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO;
12 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; 11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
13 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; 12 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
@@ -15,13 +14,13 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleUp @@ -15,13 +14,13 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleUp
15 import cn.iocoder.yudao.module.system.convert.permission.RoleConvert; 14 import cn.iocoder.yudao.module.system.convert.permission.RoleConvert;
16 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; 15 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
17 import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper; 16 import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper;
  17 +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
18 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; 18 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
19 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; 19 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
20 import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer; 20 import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer;
21 import com.google.common.annotations.VisibleForTesting; 21 import com.google.common.annotations.VisibleForTesting;
22 import lombok.Getter; 22 import lombok.Getter;
23 import lombok.extern.slf4j.Slf4j; 23 import lombok.extern.slf4j.Slf4j;
24 -import org.springframework.context.annotation.Lazy;  
25 import org.springframework.lang.Nullable; 24 import org.springframework.lang.Nullable;
26 import org.springframework.scheduling.annotation.Scheduled; 25 import org.springframework.scheduling.annotation.Scheduled;
27 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
@@ -77,53 +76,46 @@ public class RoleServiceImpl implements RoleService { @@ -77,53 +76,46 @@ public class RoleServiceImpl implements RoleService {
77 @Resource 76 @Resource
78 private RoleProducer roleProducer; 77 private RoleProducer roleProducer;
79 78
80 - @Resource  
81 - @Lazy // 注入自己,所以延迟加载  
82 - private RoleService self;  
83 -  
84 /** 79 /**
85 * 初始化 {@link #roleCache} 缓存 80 * 初始化 {@link #roleCache} 缓存
86 */ 81 */
87 @Override 82 @Override
88 @PostConstruct 83 @PostConstruct
89 - @TenantIgnore // 忽略自动多租户,全局初始化缓存  
90 public void initLocalCache() { 84 public void initLocalCache() {
91 - // 获取角色列表,如果有更新  
92 - List<RoleDO> roleList = loadRoleIfUpdate(maxUpdateTime);  
93 - if (CollUtil.isEmpty(roleList)) {  
94 - return;  
95 - }  
96 -  
97 - // 写入缓存  
98 - roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId);  
99 - maxUpdateTime = CollectionUtils.getMaxValue(roleList, RoleDO::getUpdateTime);  
100 - log.info("[initLocalCache][初始化 Role 数量为 {}]", roleList.size()); 85 + initLocalCacheIfUpdate(null);
101 } 86 }
102 87
103 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) 88 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
104 public void schedulePeriodicRefresh() { 89 public void schedulePeriodicRefresh() {
105 - self.initLocalCache(); 90 + initLocalCacheIfUpdate(this.maxUpdateTime);
106 } 91 }
107 92
108 /** 93 /**
109 - * 如果角色发生变化,从数据库中获取最新的全量角色。  
110 - * 如果未发生变化,则返回空 94 + * 刷新本地缓存
111 * 95 *
112 - * @param maxUpdateTime 当前角色的最大更新时间  
113 - * @return 角色列表 96 + * @param maxUpdateTime 最大更新时间
  97 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  98 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
114 */ 99 */
115 - private List<RoleDO> loadRoleIfUpdate(LocalDateTime maxUpdateTime) {  
116 - // 第一步,判断是否要更新。  
117 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
118 - log.info("[loadRoleIfUpdate][首次加载全量角色]");  
119 - } else { // 判断数据库中是否有更新的角色  
120 - if (roleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
121 - return null; 100 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  101 + // 注意:忽略自动多租户,因为要全局初始化缓存
  102 + TenantUtils.executeIgnore(() -> {
  103 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  104 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  105 + if (maxUpdateTime != null
  106 + && roleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  107 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  108 + return;
122 } 109 }
123 - log.info("[loadRoleIfUpdate][增量加载全量角色]");  
124 - }  
125 - // 第二步,如果有更新,则从数据库加载所有角色  
126 - return roleMapper.selectList(); 110 + List<RoleDO> roleList = roleMapper.selectList();
  111 + log.info("[initLocalCacheIfUpdate][缓存角色,数量为:{}]", roleList.size());
  112 +
  113 + // 第二步:构建缓存。
  114 + roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId);
  115 +
  116 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  117 + this.maxUpdateTime = CollectionUtils.getMaxValue(roleList, RoleDO::getUpdateTime);
  118 + });
127 } 119 }
128 120
129 @Override 121 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java
@@ -84,21 +84,42 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { @@ -84,21 +84,42 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
84 @Override 84 @Override
85 @PostConstruct 85 @PostConstruct
86 public void initLocalCache() { 86 public void initLocalCache() {
87 - // 获取敏感词列表,如果有更新  
88 - List<SensitiveWordDO> sensitiveWordList = loadSensitiveWordIfUpdate(maxUpdateTime);  
89 - if (CollUtil.isEmpty(sensitiveWordList)) { 87 + initLocalCacheIfUpdate(null);
  88 + }
  89 +
  90 + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
  91 + public void schedulePeriodicRefresh() {
  92 + initLocalCacheIfUpdate(this.maxUpdateTime);
  93 + }
  94 +
  95 + /**
  96 + * 刷新本地缓存
  97 + *
  98 + * @param maxUpdateTime 最大更新时间
  99 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  100 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
  101 + */
  102 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  103 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  104 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  105 + if (maxUpdateTime != null
  106 + && sensitiveWordMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  107 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
90 return; 108 return;
91 } 109 }
  110 + List<SensitiveWordDO> sensitiveWords = sensitiveWordMapper.selectList();
  111 + log.info("[initLocalCacheIfUpdate][缓存敏感词,数量为:{}]", sensitiveWords.size());
92 112
  113 + // 第二步:构建缓存。
93 // 写入 sensitiveWordTagsCache 缓存 114 // 写入 sensitiveWordTagsCache 缓存
94 Set<String> tags = new HashSet<>(); 115 Set<String> tags = new HashSet<>();
95 - sensitiveWordList.forEach(word -> tags.addAll(word.getTags())); 116 + sensitiveWords.forEach(word -> tags.addAll(word.getTags()));
96 sensitiveWordTagsCache = tags; 117 sensitiveWordTagsCache = tags;
97 // 写入 defaultSensitiveWordTrie、tagSensitiveWordTries 缓存 118 // 写入 defaultSensitiveWordTrie、tagSensitiveWordTries 缓存
98 - initSensitiveWordTrie(sensitiveWordList);  
99 - // 写入 maxUpdateTime 最大更新时间  
100 - maxUpdateTime = CollectionUtils.getMaxValue(sensitiveWordList, SensitiveWordDO::getUpdateTime);  
101 - log.info("[initLocalCache][初始化 敏感词 数量为 {}]", sensitiveWordList.size()); 119 + initSensitiveWordTrie(sensitiveWords);
  120 +
  121 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  122 + this.maxUpdateTime = CollectionUtils.getMaxValue(sensitiveWords, SensitiveWordDO::getUpdateTime);
102 } 123 }
103 124
104 private void initSensitiveWordTrie(List<SensitiveWordDO> wordDOs) { 125 private void initSensitiveWordTrie(List<SensitiveWordDO> wordDOs) {
@@ -122,33 +143,6 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { @@ -122,33 +143,6 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
122 this.tagSensitiveWordTries = tagSensitiveWordTries; 143 this.tagSensitiveWordTries = tagSensitiveWordTries;
123 } 144 }
124 145
125 - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)  
126 - public void schedulePeriodicRefresh() {  
127 - initLocalCache();  
128 - }  
129 -  
130 - /**  
131 - * 如果敏感词发生变化,从数据库中获取最新的全量敏感词。  
132 - * 如果未发生变化,则返回空  
133 - *  
134 - * @param maxUpdateTime 当前敏感词的最大更新时间  
135 - * @return 敏感词列表  
136 - */  
137 - private List<SensitiveWordDO> loadSensitiveWordIfUpdate(LocalDateTime maxUpdateTime) {  
138 - // 第一步,判断是否要更新。  
139 - // 如果更新时间为空,说明 DB 一定有新数据  
140 - if (maxUpdateTime == null) {  
141 - log.info("[loadSensitiveWordIfUpdate][首次加载全量敏感词]");  
142 - } else { // 判断数据库中是否有更新的敏感词  
143 - if (sensitiveWordMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
144 - return null;  
145 - }  
146 - log.info("[loadSensitiveWordIfUpdate][增量加载全量敏感词]");  
147 - }  
148 - // 第二步,如果有更新,则从数据库加载所有敏感词  
149 - return sensitiveWordMapper.selectList();  
150 - }  
151 -  
152 @Override 146 @Override
153 public Long createSensitiveWord(SensitiveWordCreateReqVO createReqVO) { 147 public Long createSensitiveWord(SensitiveWordCreateReqVO createReqVO) {
154 // 校验唯一性 148 // 校验唯一性
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelService.java
@@ -21,7 +21,7 @@ public interface SmsChannelService { @@ -21,7 +21,7 @@ public interface SmsChannelService {
21 /** 21 /**
22 * 初始化短信客户端 22 * 初始化短信客户端
23 */ 23 */
24 - void initSmsClients(); 24 + void initLocalCache();
25 25
26 /** 26 /**
27 * 创建短信渠道 27 * 创建短信渠道
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.sms; 1 package cn.iocoder.yudao.module.system.service.sms;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
6 import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; 4 import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
7 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; 5 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
8 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO;
@@ -23,14 +21,14 @@ import java.util.Collection; @@ -23,14 +21,14 @@ import java.util.Collection;
23 import java.util.List; 21 import java.util.List;
24 22
25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
26 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; 25 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
27 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; 26 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
28 27
29 /** 28 /**
30 - * 短信渠道Service实现类 29 + * 短信渠道 Service 实现类
31 * 30 *
32 * @author zzf 31 * @author zzf
33 - * @date 2021/1/25 9:25  
34 */ 32 */
35 @Service 33 @Service
36 @Slf4j 34 @Slf4j
@@ -61,46 +59,39 @@ public class SmsChannelServiceImpl implements SmsChannelService { @@ -61,46 +59,39 @@ public class SmsChannelServiceImpl implements SmsChannelService {
61 59
62 @Override 60 @Override
63 @PostConstruct 61 @PostConstruct
64 - public void initSmsClients() {  
65 - // 获取短信渠道,如果有更新  
66 - List<SmsChannelDO> smsChannels = this.loadSmsChannelIfUpdate(maxUpdateTime);  
67 - if (CollUtil.isEmpty(smsChannels)) {  
68 - return;  
69 - }  
70 -  
71 - // 创建或更新短信 Client  
72 - List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(smsChannels);  
73 - propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));  
74 -  
75 - // 写入缓存  
76 - maxUpdateTime = CollectionUtils.getMaxValue(smsChannels, SmsChannelDO::getUpdateTime);  
77 - log.info("[initSmsClients][初始化 SmsChannel 数量为 {}]", smsChannels.size()); 62 + public void initLocalCache() {
  63 + initLocalCacheIfUpdate(null);
78 } 64 }
79 65
80 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) 66 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
81 public void schedulePeriodicRefresh() { 67 public void schedulePeriodicRefresh() {
82 - initSmsClients(); 68 + initLocalCacheIfUpdate(this.maxUpdateTime);
83 } 69 }
84 70
85 /** 71 /**
86 - * 如果短信渠道发生变化,从数据库中获取最新的全量短信渠道。  
87 - * 如果未发生变化,则返回空 72 + * 刷新本地缓存
88 * 73 *
89 - * @param maxUpdateTime 当前短信渠道的最大更新时间  
90 - * @return 短信渠道列表 74 + * @param maxUpdateTime 最大更新时间
  75 + * 1. 如果 maxUpdateTime 为 null,则“强制”刷新缓存
  76 + * 2. 如果 maxUpdateTime 不为 null,判断自 maxUpdateTime 是否有数据发生变化,有的情况下才刷新缓存
91 */ 77 */
92 - private List<SmsChannelDO> loadSmsChannelIfUpdate(LocalDateTime maxUpdateTime) {  
93 - // 第一步,判断是否要更新。  
94 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据  
95 - log.info("[loadSmsChannelIfUpdate][首次加载全量短信渠道]");  
96 - } else { // 判断数据库中是否有更新的短信渠道  
97 - if (smsChannelMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {  
98 - return null;  
99 - }  
100 - log.info("[loadSmsChannelIfUpdate][增量加载全量短信渠道]"); 78 + private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
  79 + // 第一步:基于 maxUpdateTime 判断缓存是否刷新。
  80 + // 如果没有增量的数据变化,则不进行本地缓存的刷新
  81 + if (maxUpdateTime != null
  82 + && smsChannelMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
  83 + log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
  84 + return;
101 } 85 }
102 - // 第二步,如果有更新,则从数据库加载所有短信渠道  
103 - return smsChannelMapper.selectList(); 86 + List<SmsChannelDO> channels = smsChannelMapper.selectList();
  87 + log.info("[initLocalCacheIfUpdate][缓存短信渠道,数量为:{}]", channels.size());
  88 +
  89 + // 第二步:构建缓存。创建或更新短信 Client
  90 + List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(channels);
  91 + propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
  92 +
  93 + // 第三步:设置最新的 maxUpdateTime,用于下次的增量判断。
  94 + this.maxUpdateTime = getMaxValue(channels, SmsChannelDO::getUpdateTime);
104 } 95 }
105 96
106 @Override 97 @Override
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java
@@ -71,7 +71,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { @@ -71,7 +71,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
71 private PermissionProducer permissionProducer; 71 private PermissionProducer permissionProducer;
72 72
73 @Test 73 @Test
74 - public void testInitRoleMenuLocalCache() { 74 + public void testInitLocalCacheIfUpdateForRoleMenu() {
75 // mock 数据 75 // mock 数据
76 RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L)); 76 RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L));
77 roleMenuMapper.insert(roleMenuDO01); 77 roleMenuMapper.insert(roleMenuDO01);
@@ -79,7 +79,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { @@ -79,7 +79,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
79 roleMenuMapper.insert(roleMenuDO02); 79 roleMenuMapper.insert(roleMenuDO02);
80 80
81 // 调用 81 // 调用
82 - permissionService.initRoleMenuLocalCache(); 82 + permissionService.initLocalCacheIfUpdateForRoleMenu(null);
83 // 断言 roleMenuCache 缓存 83 // 断言 roleMenuCache 缓存
84 assertEquals(1, permissionService.getRoleMenuCache().keySet().size()); 84 assertEquals(1, permissionService.getRoleMenuCache().keySet().size());
85 assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L)); 85 assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L));
@@ -93,7 +93,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { @@ -93,7 +93,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
93 } 93 }
94 94
95 @Test 95 @Test
96 - public void testInitUserRoleLocalCache() { 96 + public void testInitLocalCacheIfUpdateForUserRole() {
97 // mock 数据 97 // mock 数据
98 UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); 98 UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L));
99 userRoleMapper.insert(userRoleDO01); 99 userRoleMapper.insert(userRoleDO01);
@@ -101,7 +101,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { @@ -101,7 +101,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
101 userRoleMapper.insert(roleMenuDO02); 101 userRoleMapper.insert(roleMenuDO02);
102 102
103 // 调用 103 // 调用
104 - permissionService.initUserRoleLocalCache(); 104 + permissionService.initLocalCacheIfUpdateForUserRole(null);
105 // 断言 roleMenuCache 缓存 105 // 断言 roleMenuCache 缓存
106 assertEquals(1, permissionService.getUserRoleCache().size()); 106 assertEquals(1, permissionService.getUserRoleCache().size());
107 assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L)); 107 assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L));
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java
@@ -57,7 +57,7 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { @@ -57,7 +57,7 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
57 smsChannelMapper.insert(smsChannelDO02); 57 smsChannelMapper.insert(smsChannelDO02);
58 58
59 // 调用 59 // 调用
60 - smsChannelService.initSmsClients(); 60 + smsChannelService.initLocalCache();
61 // 校验 maxUpdateTime 属性 61 // 校验 maxUpdateTime 属性
62 LocalDateTime maxUpdateTime = (LocalDateTime) BeanUtil.getFieldValue(smsChannelService, "maxUpdateTime"); 62 LocalDateTime maxUpdateTime = (LocalDateTime) BeanUtil.getFieldValue(smsChannelService, "maxUpdateTime");
63 assertEquals(max(smsChannelDO01.getUpdateTime(), smsChannelDO02.getUpdateTime()), maxUpdateTime); 63 assertEquals(max(smsChannelDO01.getUpdateTime(), smsChannelDO02.getUpdateTime()), maxUpdateTime);