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

This commit is contained in:
YunaiV 2022-12-29 00:11:11 +08:00
parent 81340a636b
commit 6f8ca56e16
16 changed files with 276 additions and 322 deletions

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.framework.tenant.core.aop; package cn.iocoder.yudao.framework.tenant.core.aop;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
@ -11,6 +12,8 @@ import org.aspectj.lang.annotation.Aspect;
* 例如说一个定时任务读取所有数据进行处理 * 例如说一个定时任务读取所有数据进行处理
* 又例如说读取所有数据进行缓存 * 又例如说读取所有数据进行缓存
* *
* 整体逻辑的实现 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致
*
* @author 芋道源码 * @author 芋道源码
*/ */
@Aspect @Aspect

View File

@ -34,6 +34,22 @@ public class TenantUtils {
} }
} }
/**
* 忽略租户执行对应的逻辑
*
* @param runnable 逻辑
*/
public static void executeIgnore(Runnable runnable) {
Boolean oldIgnore = TenantContextHolder.isIgnore();
try {
TenantContextHolder.setIgnore(true);
// 执行逻辑
runnable.run();
} finally {
TenantContextHolder.setIgnore(oldIgnore);
}
}
/** /**
* 使用指定租户执行对应的逻辑 * 使用指定租户执行对应的逻辑
* *

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.infra.service.file; 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.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -79,20 +77,36 @@ public class FileConfigServiceImpl implements FileConfigService {
@Resource @Resource
private Validator validator; private Validator validator;
@Resource
@Lazy // 注入自己所以延迟加载
private FileConfigService self;
@Override @Override
@PostConstruct @PostConstruct
public void initFileClients() { public void initFileClients() {
// 获取文件配置如果有更新 initLocalCacheIfUpdate(null);
List<FileConfigDO> configs = loadFileConfigIfUpdate(maxUpdateTime);
if (CollUtil.isEmpty(configs)) {
return;
} }
// 创建或更新支付 Client @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& fileConfigMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<FileConfigDO> configs = fileConfigMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存文件配置,数量为:{}]", configs.size());
// 第二步构建缓存创建或更新文件 Client
configs.forEach(config -> { configs.forEach(config -> {
fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
// 如果是 master进行设置 // 如果是 master进行设置
@ -101,35 +115,8 @@ public class FileConfigServiceImpl implements FileConfigService {
} }
}); });
// 写入缓存 // 第三步设置最新的 maxUpdateTime用于下次的增量判断
maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime); this.maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime);
log.info("[initFileClients][初始化 FileConfig 数量为 {}]", configs.size());
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
self.initFileClients();
}
/**
* 如果文件配置发生变化从数据库中获取最新的全量文件配置
* 如果未发生变化则返回空
*
* @param maxUpdateTime 当前文件配置的最大更新时间
* @return 文件配置列表
*/
private List<FileConfigDO> loadFileConfigIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据
log.info("[loadFileConfigIfUpdate][首次加载全量文件配置]");
} else { // 判断数据库中是否有更新的文件配置
if (fileConfigMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadFileConfigIfUpdate][增量加载全量文件配置]");
}
// 第二步如果有更新则从数据库加载所有文件配置
return fileConfigMapper.selectList();
} }
@Override @Override

View File

@ -240,7 +240,7 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
// mock 获得 Client // mock 获得 Client
FileClient fileClient = mock(FileClient.class); FileClient fileClient = mock(FileClient.class);
when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient);
when(fileClient.upload(any(), any())).thenReturn("https://www.iocoder.cn"); when(fileClient.upload(any(), any(), any())).thenReturn("https://www.iocoder.cn");
// 调用并断言 // 调用并断言
assertEquals("https://www.iocoder.cn", fileConfigService.testFileConfig(id)); assertEquals("https://www.iocoder.cn", fileConfigService.testFileConfig(id));

View File

@ -78,7 +78,7 @@ public class FileServiceTest extends BaseDbUnitTest {
FileClient client = mock(FileClient.class); FileClient client = mock(FileClient.class);
when(fileConfigService.getMasterFileClient()).thenReturn(client); when(fileConfigService.getMasterFileClient()).thenReturn(client);
String url = randomString(); String url = randomString();
when(client.upload(same(content), same(path))).thenReturn(url); when(client.upload(same(content), same(path), same("image/jpeg"))).thenReturn(url);
when(client.getId()).thenReturn(10L); when(client.getId()).thenReturn(10L);
String name = "单测文件名"; String name = "单测文件名";
// 调用 // 调用

View File

@ -23,7 +23,7 @@ public class SmsChannelRefreshConsumer {
@EventListener @EventListener
public void execute(SmsChannelRefreshMessage message) { public void execute(SmsChannelRefreshMessage message) {
log.info("[execute][收到 SmsChannel 刷新消息]"); log.info("[execute][收到 SmsChannel 刷新消息]");
smsChannelService.initSmsClients(); smsChannelService.initLocalCache();
} }
} }

View File

@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO;
@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -73,58 +72,55 @@ public class DeptServiceImpl implements DeptService {
@Resource @Resource
private DeptProducer deptProducer; private DeptProducer deptProducer;
@Resource /**
@Lazy // 注入自己所以延迟加载 * 初始化 {@link #parentDeptCache} {@link #deptCache} 缓存
private DeptService self; */
@Override @Override
@PostConstruct @PostConstruct
@TenantIgnore // 初始化缓存无需租户过滤
public synchronized void initLocalCache() { public synchronized void initLocalCache() {
// 获取部门列表如果有更新 initLocalCacheIfUpdate(null);
List<DeptDO> deptList = loadDeptIfUpdate(maxUpdateTime);
if (CollUtil.isEmpty(deptList)) {
return;
} }
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 注意忽略自动多租户因为要全局初始化缓存
TenantUtils.executeIgnore(() -> {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& deptMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<DeptDO> depts = deptMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存部门,数量为:{}]", depts.size());
// 第二步构建缓存创建或更新支付 Client
// 构建缓存 // 构建缓存
ImmutableMap.Builder<Long, DeptDO> builder = ImmutableMap.builder(); ImmutableMap.Builder<Long, DeptDO> builder = ImmutableMap.builder();
ImmutableMultimap.Builder<Long, DeptDO> parentBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, DeptDO> parentBuilder = ImmutableMultimap.builder();
deptList.forEach(sysRoleDO -> { depts.forEach(sysRoleDO -> {
builder.put(sysRoleDO.getId(), sysRoleDO); builder.put(sysRoleDO.getId(), sysRoleDO);
parentBuilder.put(sysRoleDO.getParentId(), sysRoleDO); parentBuilder.put(sysRoleDO.getParentId(), sysRoleDO);
}); });
// 设置缓存 // 设置缓存
deptCache = builder.build(); deptCache = builder.build();
parentDeptCache = parentBuilder.build(); parentDeptCache = parentBuilder.build();
maxUpdateTime = CollectionUtils.getMaxValue(deptList, DeptDO::getUpdateTime);
log.info("[initLocalCache][初始化 Dept 数量为 {}]", deptList.size());
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) // 第三步设置最新的 maxUpdateTime用于下次的增量判断
public void schedulePeriodicRefresh() { this.maxUpdateTime = CollectionUtils.getMaxValue(depts, DeptDO::getUpdateTime);
self.initLocalCache(); });
}
/**
* 如果部门发生变化从数据库中获取最新的全量部门
* 如果未发生变化则返回空
*
* @param maxUpdateTime 当前部门的最大更新时间
* @return 部门列表
*/
protected List<DeptDO> loadDeptIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据
log.info("[loadMenuIfUpdate][首次加载全量部门]");
} else { // 判断数据库中是否有更新的部门
if (deptMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadMenuIfUpdate][增量加载全量部门]");
}
// 第二步如果有更新则从数据库加载所有部门
return deptMapper.selectList();
} }
@Override @Override

View File

@ -25,7 +25,6 @@ import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -77,42 +76,37 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
// 获取客户端列表如果有更新 initLocalCacheIfUpdate(null);
List<OAuth2ClientDO> tenantList = loadOAuth2ClientIfUpdate(maxUpdateTime);
if (CollUtil.isEmpty(tenantList)) {
return;
}
// 写入缓存
clientCache = convertMap(tenantList, OAuth2ClientDO::getClientId);
maxUpdateTime = getMaxValue(tenantList, OAuth2ClientDO::getUpdateTime);
log.info("[initLocalCache][初始化 OAuth2Client 数量为 {}]", tenantList.size());
} }
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() { public void schedulePeriodicRefresh() {
initLocalCache(); initLocalCacheIfUpdate(this.maxUpdateTime);
} }
/** /**
* 如果客户端发生变化从数据库中获取最新的全量客户端 * 刷新本地缓存
* 如果未发生变化则返回空
* *
* @param maxUpdateTime 当前客户端的最大更新时间 * @param maxUpdateTime 最大更新时间
* @return 客户端列表 * 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/ */
private List<OAuth2ClientDO> loadOAuth2ClientIfUpdate(LocalDateTime maxUpdateTime) { private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更 // 第一步基于 maxUpdateTime 判断缓存是否刷
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据 // 如果没有增量的数据变化则不进行本地缓存的刷新
log.info("[loadOAuth2ClientIfUpdate][首次加载全量客户端]"); if (maxUpdateTime != null
} else { // 判断数据库中是否有更新的客户端 && oauth2ClientMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
if (oauth2ClientMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return null; return;
} }
log.info("[loadOAuth2ClientIfUpdate][增量加载全量客户端]"); List<OAuth2ClientDO> clients = oauth2ClientMapper.selectList();
} log.info("[initLocalCacheIfUpdate][缓存 OAuth2 客户端,数量为:{}]", clients.size());
// 第二步如果有更新则从数据库加载所有客户端
return oauth2ClientMapper.selectList(); // 第二步构建缓存
clientCache = convertMap(clients, OAuth2ClientDO::getClientId);
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = getMaxValue(clients, OAuth2ClientDO::getUpdateTime);
} }
@Override @Override

View File

@ -86,13 +86,33 @@ public class MenuServiceImpl implements MenuService {
@Override @Override
@PostConstruct @PostConstruct
public synchronized void initLocalCache() { public synchronized void initLocalCache() {
// 获取菜单列表如果有更新 initLocalCacheIfUpdate(null);
List<MenuDO> menuList = this.loadMenuIfUpdate(maxUpdateTime);
if (CollUtil.isEmpty(menuList)) {
return;
} }
// 构建缓存 @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& menuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<MenuDO> menuList = menuMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存菜单,数量为:{}]", menuList.size());
// 第二步构建缓存
ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder(); ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder();
ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder();
menuList.forEach(menuDO -> { menuList.forEach(menuDO -> {
@ -103,34 +123,9 @@ public class MenuServiceImpl implements MenuService {
}); });
menuCache = menuCacheBuilder.build(); menuCache = menuCacheBuilder.build();
permissionMenuCache = permMenuCacheBuilder.build(); permissionMenuCache = permMenuCacheBuilder.build();
maxUpdateTime = CollectionUtils.getMaxValue(menuList, MenuDO::getUpdateTime);
log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size());
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) // 第三步设置最新的 maxUpdateTime用于下次的增量判断
public void schedulePeriodicRefresh() { this.maxUpdateTime = CollectionUtils.getMaxValue(menuList, MenuDO::getUpdateTime);
initLocalCache();
}
/**
* 如果菜单发生变化从数据库中获取最新的全量菜单
* 如果未发生变化则返回空
*
* @param maxUpdateTime 当前菜单的最大更新时间
* @return 菜单列表
*/
private List<MenuDO> loadMenuIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据
log.info("[loadMenuIfUpdate][首次加载全量菜单]");
} else { // 判断数据库中是否有更新的菜单
if (menuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadMenuIfUpdate][增量加载全量菜单]");
}
// 第二步如果有更新则从数据库加载所有菜单
return menuMapper.selectList();
} }
@Override @Override

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@ -31,7 +32,6 @@ import com.google.common.collect.Sets;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -126,106 +126,84 @@ public class PermissionServiceImpl implements PermissionService {
@Resource @Resource
private PermissionProducer permissionProducer; private PermissionProducer permissionProducer;
@Resource
@Lazy // 注入自己所以延迟加载
private PermissionService self;
@Override @Override
@PostConstruct @PostConstruct
@TenantIgnore // 初始化缓存无需租户过滤
public void initLocalCache() { public void initLocalCache() {
initUserRoleLocalCache(); initLocalCacheIfUpdateForRoleMenu(null);
initRoleMenuLocalCache(); initLocalCacheIfUpdateForUserRole(null);
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdateForRoleMenu(this.roleMenuMaxUpdateTime);
initLocalCacheIfUpdateForUserRole(this.userRoleMaxUpdateTime);
} }
/** /**
* 初始化 {@link #roleMenuCache} {@link #menuRoleCache} 缓存 * 刷新 RoleMenu 本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/ */
@VisibleForTesting @VisibleForTesting
void initRoleMenuLocalCache() { void initLocalCacheIfUpdateForRoleMenu(LocalDateTime maxUpdateTime) {
// 获取角色与菜单的关联列表如果有更新 // 注意忽略自动多租户因为要全局初始化缓存
List<RoleMenuDO> roleMenuList = loadRoleMenuIfUpdate(roleMenuMaxUpdateTime); TenantUtils.executeIgnore(() -> {
if (CollUtil.isEmpty(roleMenuList)) { // 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& roleMenuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdateForRoleMenu][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return; return;
} }
List<RoleMenuDO> roleMenus = roleMenuMapper.selectList();
log.info("[initLocalCacheIfUpdateForRoleMenu][缓存角色与菜单,数量为:{}]", roleMenus.size());
// 初始化 roleMenuCache menuRoleCache 缓存 // 第二步构建缓存
ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder();
ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder();
roleMenuList.forEach(roleMenuDO -> { roleMenus.forEach(roleMenuDO -> {
roleMenuCacheBuilder.put(roleMenuDO.getRoleId(), roleMenuDO.getMenuId()); roleMenuCacheBuilder.put(roleMenuDO.getRoleId(), roleMenuDO.getMenuId());
menuRoleCacheBuilder.put(roleMenuDO.getMenuId(), roleMenuDO.getRoleId()); menuRoleCacheBuilder.put(roleMenuDO.getMenuId(), roleMenuDO.getRoleId());
}); });
roleMenuCache = roleMenuCacheBuilder.build(); roleMenuCache = roleMenuCacheBuilder.build();
menuRoleCache = menuRoleCacheBuilder.build(); menuRoleCache = menuRoleCacheBuilder.build();
roleMenuMaxUpdateTime = getMaxValue(roleMenuList, RoleMenuDO::getUpdateTime);
log.info("[initRoleMenuLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); // 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.roleMenuMaxUpdateTime = getMaxValue(roleMenus, RoleMenuDO::getUpdateTime);
});
} }
/** /**
* 初始化 {@link #userRoleCache} 缓存 * 刷新 UserRole 本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/ */
@VisibleForTesting @VisibleForTesting
void initUserRoleLocalCache() { void initLocalCacheIfUpdateForUserRole(LocalDateTime maxUpdateTime) {
// 获取用户与角色的关联列表如果有更新 // 注意忽略自动多租户因为要全局初始化缓存
List<UserRoleDO> userRoleList = loadUserRoleIfUpdate(userRoleMaxUpdateTime); TenantUtils.executeIgnore(() -> {
if (CollUtil.isEmpty(userRoleList)) { // 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& userRoleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdateForUserRole][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return; return;
} }
List<UserRoleDO> userRoles = userRoleMapper.selectList();
log.info("[initLocalCacheIfUpdateForUserRole][缓存用户与角色,数量为:{}]", userRoles.size());
// 初始化 userRoleCache 缓存 // 第二步构建缓存
ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder(); ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder();
userRoleList.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId())); userRoles.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId()));
userRoleCache = CollectionUtils.convertMultiMap2(userRoleList, UserRoleDO::getUserId, UserRoleDO::getRoleId); userRoleCache = CollectionUtils.convertMultiMap2(userRoles, UserRoleDO::getUserId, UserRoleDO::getRoleId);
userRoleMaxUpdateTime = getMaxValue(userRoleList, UserRoleDO::getUpdateTime);
log.info("[initUserRoleLocalCache][初始化用户与角色的关联数量为 {}]", userRoleList.size());
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) // 第三步设置最新的 maxUpdateTime用于下次的增量判断
public void schedulePeriodicRefresh() { this.userRoleMaxUpdateTime = getMaxValue(userRoles, UserRoleDO::getUpdateTime);
self.initLocalCache(); });
}
/**
* 如果角色与菜单的关联发生变化从数据库中获取最新的全量角色与菜单的关联
* 如果未发生变化则返回空
*
* @param maxUpdateTime 当前角色与菜单的关联的最大更新时间
* @return 角色与菜单的关联列表
*/
protected List<RoleMenuDO> loadRoleMenuIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据
log.info("[loadRoleMenuIfUpdate][首次加载全量角色与菜单的关联]");
} else { // 判断数据库中是否有更新的角色与菜单的关联
if (roleMenuMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadRoleMenuIfUpdate][增量加载全量角色与菜单的关联]");
}
// 第二步如果有更新则从数据库加载所有角色与菜单的关联
return roleMenuMapper.selectList();
}
/**
* 如果用户与角色的关联发生变化从数据库中获取最新的全量用户与角色的关联
* 如果未发生变化则返回空
*
* @param maxUpdateTime 当前角色与菜单的关联的最大更新时间
* @return 角色与菜单的关联列表
*/
protected List<UserRoleDO> loadUserRoleIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据
log.info("[loadUserRoleIfUpdate][首次加载全量用户与角色的关联]");
} else { // 判断数据库中是否有更新的用户与角色的关联
if (userRoleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadUserRoleIfUpdate][增量加载全量用户与角色的关联]");
}
// 第二步如果有更新则从数据库加载所有用户与角色的关联
return userRoleMapper.selectList();
} }
@Override @Override

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
@ -86,44 +87,41 @@ public class RoleServiceImpl implements RoleService {
*/ */
@Override @Override
@PostConstruct @PostConstruct
@TenantIgnore // 忽略自动多租户全局初始化缓存
public void initLocalCache() { public void initLocalCache() {
// 获取角色列表如果有更新 initLocalCacheIfUpdate(null);
List<RoleDO> roleList = loadRoleIfUpdate(maxUpdateTime);
if (CollUtil.isEmpty(roleList)) {
return;
}
// 写入缓存
roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId);
maxUpdateTime = CollectionUtils.getMaxValue(roleList, RoleDO::getUpdateTime);
log.info("[initLocalCache][初始化 Role 数量为 {}]", roleList.size());
} }
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() { public void schedulePeriodicRefresh() {
self.initLocalCache(); initLocalCacheIfUpdate(this.maxUpdateTime);
} }
/** /**
* 如果角色发生变化从数据库中获取最新的全量角色 * 刷新本地缓存
* 如果未发生变化则返回空
* *
* @param maxUpdateTime 当前角色的最大更新时间 * @param maxUpdateTime 最大更新时间
* @return 角色列表 * 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/ */
private List<RoleDO> loadRoleIfUpdate(LocalDateTime maxUpdateTime) { private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新 // 注意忽略自动多租户因为要全局初始化缓存
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据 TenantUtils.executeIgnore(() -> {
log.info("[loadRoleIfUpdate][首次加载全量角色]"); // 第一步基于 maxUpdateTime 判断缓存是否刷新
} else { // 判断数据库中是否有更新的角色 // 如果没有增量的数据变化则不进行本地缓存的刷新
if (roleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { if (maxUpdateTime != null
return null; && roleMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
} }
log.info("[loadRoleIfUpdate][增量加载全量角色]"); List<RoleDO> roleList = roleMapper.selectList();
} log.info("[initLocalCacheIfUpdate][缓存角色,数量为:{}]", roleList.size());
// 第二步如果有更新则从数据库加载所有角色
return roleMapper.selectList(); // 第二步构建缓存
roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId);
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = CollectionUtils.getMaxValue(roleList, RoleDO::getUpdateTime);
});
} }
@Override @Override

View File

@ -84,21 +84,42 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
@Override @Override
@PostConstruct @PostConstruct
public void initLocalCache() { public void initLocalCache() {
// 获取敏感词列表如果有更新 initLocalCacheIfUpdate(null);
List<SensitiveWordDO> sensitiveWordList = loadSensitiveWordIfUpdate(maxUpdateTime);
if (CollUtil.isEmpty(sensitiveWordList)) {
return;
} }
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCacheIfUpdate(this.maxUpdateTime);
}
/**
* 刷新本地缓存
*
* @param maxUpdateTime 最大更新时间
* 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/
private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步基于 maxUpdateTime 判断缓存是否刷新
// 如果没有增量的数据变化则不进行本地缓存的刷新
if (maxUpdateTime != null
&& sensitiveWordMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return;
}
List<SensitiveWordDO> sensitiveWords = sensitiveWordMapper.selectList();
log.info("[initLocalCacheIfUpdate][缓存敏感词,数量为:{}]", sensitiveWords.size());
// 第二步构建缓存
// 写入 sensitiveWordTagsCache 缓存 // 写入 sensitiveWordTagsCache 缓存
Set<String> tags = new HashSet<>(); Set<String> tags = new HashSet<>();
sensitiveWordList.forEach(word -> tags.addAll(word.getTags())); sensitiveWords.forEach(word -> tags.addAll(word.getTags()));
sensitiveWordTagsCache = tags; sensitiveWordTagsCache = tags;
// 写入 defaultSensitiveWordTrietagSensitiveWordTries 缓存 // 写入 defaultSensitiveWordTrietagSensitiveWordTries 缓存
initSensitiveWordTrie(sensitiveWordList); initSensitiveWordTrie(sensitiveWords);
// 写入 maxUpdateTime 最大更新时间
maxUpdateTime = CollectionUtils.getMaxValue(sensitiveWordList, SensitiveWordDO::getUpdateTime); // 第三步设置最新的 maxUpdateTime用于下次的增量判断
log.info("[initLocalCache][初始化 敏感词 数量为 {}]", sensitiveWordList.size()); this.maxUpdateTime = CollectionUtils.getMaxValue(sensitiveWords, SensitiveWordDO::getUpdateTime);
} }
private void initSensitiveWordTrie(List<SensitiveWordDO> wordDOs) { private void initSensitiveWordTrie(List<SensitiveWordDO> wordDOs) {
@ -122,33 +143,6 @@ public class SensitiveWordServiceImpl implements SensitiveWordService {
this.tagSensitiveWordTries = tagSensitiveWordTries; this.tagSensitiveWordTries = tagSensitiveWordTries;
} }
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() {
initLocalCache();
}
/**
* 如果敏感词发生变化从数据库中获取最新的全量敏感词
* 如果未发生变化则返回空
*
* @param maxUpdateTime 当前敏感词的最大更新时间
* @return 敏感词列表
*/
private List<SensitiveWordDO> loadSensitiveWordIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更新
// 如果更新时间为空说明 DB 一定有新数据
if (maxUpdateTime == null) {
log.info("[loadSensitiveWordIfUpdate][首次加载全量敏感词]");
} else { // 判断数据库中是否有更新的敏感词
if (sensitiveWordMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
return null;
}
log.info("[loadSensitiveWordIfUpdate][增量加载全量敏感词]");
}
// 第二步如果有更新则从数据库加载所有敏感词
return sensitiveWordMapper.selectList();
}
@Override @Override
public Long createSensitiveWord(SensitiveWordCreateReqVO createReqVO) { public Long createSensitiveWord(SensitiveWordCreateReqVO createReqVO) {
// 校验唯一性 // 校验唯一性

View File

@ -21,7 +21,7 @@ public interface SmsChannelService {
/** /**
* 初始化短信客户端 * 初始化短信客户端
*/ */
void initSmsClients(); void initLocalCache();
/** /**
* 创建短信渠道 * 创建短信渠道

View File

@ -23,6 +23,7 @@ import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
@ -30,7 +31,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNE
* 短信渠道Service实现类 * 短信渠道Service实现类
* *
* @author zzf * @author zzf
* @date 2021/1/25 9:25
*/ */
@Service @Service
@Slf4j @Slf4j
@ -61,46 +61,39 @@ public class SmsChannelServiceImpl implements SmsChannelService {
@Override @Override
@PostConstruct @PostConstruct
public void initSmsClients() { public void initLocalCache() {
// 获取短信渠道如果有更新 initLocalCacheIfUpdate(null);
List<SmsChannelDO> smsChannels = this.loadSmsChannelIfUpdate(maxUpdateTime);
if (CollUtil.isEmpty(smsChannels)) {
return;
}
// 创建或更新短信 Client
List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(smsChannels);
propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
// 写入缓存
maxUpdateTime = CollectionUtils.getMaxValue(smsChannels, SmsChannelDO::getUpdateTime);
log.info("[initSmsClients][初始化 SmsChannel 数量为 {}]", smsChannels.size());
} }
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void schedulePeriodicRefresh() { public void schedulePeriodicRefresh() {
initSmsClients(); initLocalCacheIfUpdate(this.maxUpdateTime);
} }
/** /**
* 如果短信渠道发生变化从数据库中获取最新的全量短信渠道 * 刷新本地缓存
* 如果未发生变化则返回空
* *
* @param maxUpdateTime 当前短信渠道的最大更新时间 * @param maxUpdateTime 最大更新时间
* @return 短信渠道列表 * 1. 如果 maxUpdateTime null强制刷新缓存
* 2. 如果 maxUpdateTime 不为 null判断自 maxUpdateTime 是否有数据发生变化有的情况下才刷新缓存
*/ */
private List<SmsChannelDO> loadSmsChannelIfUpdate(LocalDateTime maxUpdateTime) { private void initLocalCacheIfUpdate(LocalDateTime maxUpdateTime) {
// 第一步判断是否要更 // 第一步基于 maxUpdateTime 判断缓存是否刷
if (maxUpdateTime == null) { // 如果更新时间为空说明 DB 一定有新数据 // 如果没有增量的数据变化则不进行本地缓存的刷新
log.info("[loadSmsChannelIfUpdate][首次加载全量短信渠道]"); if (maxUpdateTime != null
} else { // 判断数据库中是否有更新的短信渠道 && smsChannelMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) {
if (smsChannelMapper.selectCountByUpdateTimeGt(maxUpdateTime) == 0) { log.info("[initLocalCacheIfUpdate][数据未发生变化({}),本地缓存不刷新]", maxUpdateTime);
return null; return;
} }
log.info("[loadSmsChannelIfUpdate][增量加载全量短信渠道]"); List<SmsChannelDO> channels = smsChannelMapper.selectList();
} log.info("[initLocalCacheIfUpdate][缓存短信渠道,数量为:{}]", channels.size());
// 第二步如果有更新则从数据库加载所有短信渠道
return smsChannelMapper.selectList(); // 第二步构建缓存创建或更新短信 Client
List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(channels);
propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
// 第三步设置最新的 maxUpdateTime用于下次的增量判断
this.maxUpdateTime = getMaxValue(channels, SmsChannelDO::getUpdateTime);
} }
@Override @Override

View File

@ -71,7 +71,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
private PermissionProducer permissionProducer; private PermissionProducer permissionProducer;
@Test @Test
public void testInitRoleMenuLocalCache() { public void testInitLocalCacheIfUpdateForRoleMenu() {
// mock 数据 // mock 数据
RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L)); RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L));
roleMenuMapper.insert(roleMenuDO01); roleMenuMapper.insert(roleMenuDO01);
@ -79,7 +79,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
roleMenuMapper.insert(roleMenuDO02); roleMenuMapper.insert(roleMenuDO02);
// 调用 // 调用
permissionService.initRoleMenuLocalCache(); permissionService.initLocalCacheIfUpdateForRoleMenu(null);
// 断言 roleMenuCache 缓存 // 断言 roleMenuCache 缓存
assertEquals(1, permissionService.getRoleMenuCache().keySet().size()); assertEquals(1, permissionService.getRoleMenuCache().keySet().size());
assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L)); assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L));
@ -93,7 +93,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
} }
@Test @Test
public void testInitUserRoleLocalCache() { public void testInitLocalCacheIfUpdateForUserRole() {
// mock 数据 // mock 数据
UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L));
userRoleMapper.insert(userRoleDO01); userRoleMapper.insert(userRoleDO01);
@ -101,7 +101,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
userRoleMapper.insert(roleMenuDO02); userRoleMapper.insert(roleMenuDO02);
// 调用 // 调用
permissionService.initUserRoleLocalCache(); permissionService.initLocalCacheIfUpdateForUserRole(null);
// 断言 roleMenuCache 缓存 // 断言 roleMenuCache 缓存
assertEquals(1, permissionService.getUserRoleCache().size()); assertEquals(1, permissionService.getUserRoleCache().size());
assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L)); assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L));

View File

@ -57,7 +57,7 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
smsChannelMapper.insert(smsChannelDO02); smsChannelMapper.insert(smsChannelDO02);
// 调用 // 调用
smsChannelService.initSmsClients(); smsChannelService.initLocalCache();
// 校验 maxUpdateTime 属性 // 校验 maxUpdateTime 属性
LocalDateTime maxUpdateTime = (LocalDateTime) BeanUtil.getFieldValue(smsChannelService, "maxUpdateTime"); LocalDateTime maxUpdateTime = (LocalDateTime) BeanUtil.getFieldValue(smsChannelService, "maxUpdateTime");
assertEquals(max(smsChannelDO01.getUpdateTime(), smsChannelDO02.getUpdateTime()), maxUpdateTime); assertEquals(max(smsChannelDO01.getUpdateTime(), smsChannelDO02.getUpdateTime()), maxUpdateTime);