This commit is contained in:
YunaiV 2024-02-27 22:12:05 +08:00
commit 5517dc7d4a
12 changed files with 56 additions and 23 deletions

View File

@ -1,12 +1,10 @@
package cn.iocoder.yudao.framework.common.util.cache; package cn.iocoder.yudao.framework.common.util.cache;
import com.alibaba.ttl.threadpool.TtlExecutors;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
/** /**
@ -16,14 +14,36 @@ import java.util.concurrent.Executors;
*/ */
public class CacheUtils { public class CacheUtils {
/**
* 构建异步刷新的 LoadingCache 对象
*
* 注意如果你的缓存和 ThreadLocal 有关系要么自己处理 ThreadLocal 的传递要么使用 {@link #buildCache(Duration, CacheLoader)} 方法
*
* 或者简单理解
* 1相关的使用 {@link #buildCache(Duration, CacheLoader)} 方法
* 2全局系统相关的使用当前缓存方法
*
* @param duration 过期时间
* @param loader CacheLoader 对象
* @return LoadingCache 对象
*/
public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) { public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) {
Executor executor = Executors.newCachedThreadPool( // TODO 芋艿可能要思考下未来要不要做成可配置
TtlExecutors.getDefaultDisableInheritableThreadFactory()); // TTL 保证 ThreadLocal 可以透传
return CacheBuilder.newBuilder() return CacheBuilder.newBuilder()
// 只阻塞当前数据加载线程其他线程返回旧值 // 只阻塞当前数据加载线程其他线程返回旧值
.refreshAfterWrite(duration) .refreshAfterWrite(duration)
// 通过 asyncReloading 实现全异步加载包括 refreshAfterWrite 被阻塞的加载线程 // 通过 asyncReloading 实现全异步加载包括 refreshAfterWrite 被阻塞的加载线程
.build(CacheLoader.asyncReloading(loader, executor)); .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿可能要思考下未来要不要做成可配置
}
/**
* 构建同步刷新的 LoadingCache 对象
*
* @param duration 过期时间
* @param loader CacheLoader 对象
* @return LoadingCache 对象
*/
public static <K, V> LoadingCache<K, V> buildCache(Duration duration, CacheLoader<K, V> loader) {
return CacheBuilder.newBuilder().refreshAfterWrite(duration).build(loader);
} }
} }

View File

@ -12,6 +12,8 @@ import lombok.extern.slf4j.Slf4j;
import java.time.Duration; import java.time.Duration;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
/** /**
* 字典工具类 * 字典工具类
* *
@ -27,7 +29,7 @@ public class DictFrameworkUtils {
/** /**
* 针对 {@link #getDictDataLabel(String, String)} 的缓存 * 针对 {@link #getDictDataLabel(String, String)} 的缓存
*/ */
private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> GET_DICT_DATA_CACHE = CacheUtils.buildAsyncReloadingCache( private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> GET_DICT_DATA_CACHE = buildAsyncReloadingCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟 Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() { new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {
@ -42,7 +44,7 @@ public class DictFrameworkUtils {
/** /**
* 针对 {@link #parseDictDataValue(String, String)} 的缓存 * 针对 {@link #parseDictDataValue(String, String)} 的缓存
*/ */
private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> PARSE_DICT_DATA_CACHE = CacheUtils.buildAsyncReloadingCache( private static final LoadingCache<KeyValue<String, String>, DictDataRespDTO> PARSE_DICT_DATA_CACHE = buildAsyncReloadingCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟 Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() { new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {

View File

@ -11,6 +11,8 @@ import lombok.SneakyThrows;
import java.time.Duration; import java.time.Duration;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
/** /**
* Tenant 框架 Service 实现类 * Tenant 框架 Service 实现类
* *
@ -24,7 +26,7 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
/** /**
* 针对 {@link #getTenantIds()} 的缓存 * 针对 {@link #getTenantIds()} 的缓存
*/ */
private final LoadingCache<Object, List<Long>> getTenantIdsCache = CacheUtils.buildAsyncReloadingCache( private final LoadingCache<Object, List<Long>> getTenantIdsCache = buildAsyncReloadingCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟 Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<Object, List<Long>>() { new CacheLoader<Object, List<Long>>() {
@ -38,7 +40,7 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
/** /**
* 针对 {@link #validTenant(Long)} 的缓存 * 针对 {@link #validTenant(Long)} 的缓存
*/ */
private final LoadingCache<Long, CommonResult<Boolean>> validTenantCache = CacheUtils.buildAsyncReloadingCache( private final LoadingCache<Long, CommonResult<Boolean>> validTenantCache = buildAsyncReloadingCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟 Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<Long, CommonResult<Boolean>>() { new CacheLoader<Long, CommonResult<Boolean>>() {

View File

@ -20,6 +20,8 @@ import java.time.Duration;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/** /**
@ -35,7 +37,7 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
/** /**
* 针对 {@link #hasAnyRoles(String...)} 的缓存 * 针对 {@link #hasAnyRoles(String...)} 的缓存
*/ */
private final LoadingCache<KeyValue<Long, List<String>>, Boolean> hasAnyRolesCache = CacheUtils.buildAsyncReloadingCache( private final LoadingCache<KeyValue<Long, List<String>>, Boolean> hasAnyRolesCache = buildCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟 Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<KeyValue<Long, List<String>>, Boolean>() { new CacheLoader<KeyValue<Long, List<String>>, Boolean>() {
@ -49,7 +51,7 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
/** /**
* 针对 {@link #hasAnyPermissions(String...)} 的缓存 * 针对 {@link #hasAnyPermissions(String...)} 的缓存
*/ */
private final LoadingCache<KeyValue<Long, List<String>>, Boolean> hasAnyPermissionsCache = CacheUtils.buildAsyncReloadingCache( private final LoadingCache<KeyValue<Long, List<String>>, Boolean> hasAnyPermissionsCache = buildCache(
Duration.ofMinutes(1L), // 过期时间 1 分钟 Duration.ofMinutes(1L), // 过期时间 1 分钟
new CacheLoader<KeyValue<Long, List<String>>, Boolean>() { new CacheLoader<KeyValue<Long, List<String>>, Boolean>() {

View File

@ -26,6 +26,9 @@ import java.time.Duration;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache;
/** /**
* Token 过滤器验证 token 的有效性 * Token 过滤器验证 token 的有效性
* 1. 验证通过时 userIduserTypetenantId 通过 Header 转发给服务 * 1. 验证通过时 userIduserTypetenantId 通过 Header 转发给服务
@ -59,7 +62,7 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered {
* key1多租户的编号 * key1多租户的编号
* key2访问令牌 * key2访问令牌
*/ */
private final LoadingCache<KeyValue<Long, String>, LoginUser> loginUserCache = CacheUtils.buildAsyncReloadingCache(Duration.ofMinutes(1), private final LoadingCache<KeyValue<Long, String>, LoginUser> loginUserCache = buildAsyncReloadingCache(Duration.ofMinutes(1),
new CacheLoader<KeyValue<Long, String>, LoginUser>() { new CacheLoader<KeyValue<Long, String>, LoginUser>() {
@Override @Override

View File

@ -31,6 +31,7 @@ import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "用户 App - 砍价活动") @Tag(name = "用户 App - 砍价活动")
@ -42,7 +43,7 @@ public class AppBargainActivityController {
/** /**
* {@link AppBargainActivityRespVO} 缓存通过它异步刷新 {@link #getBargainActivityList0(Integer)} 所要的首页数据 * {@link AppBargainActivityRespVO} 缓存通过它异步刷新 {@link #getBargainActivityList0(Integer)} 所要的首页数据
*/ */
private final LoadingCache<Integer, List<AppBargainActivityRespVO>> bargainActivityListCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), private final LoadingCache<Integer, List<AppBargainActivityRespVO>> bargainActivityListCache = buildCache(Duration.ofSeconds(10L),
new CacheLoader<Integer, List<AppBargainActivityRespVO>>() { new CacheLoader<Integer, List<AppBargainActivityRespVO>>() {
@Override @Override

View File

@ -32,6 +32,7 @@ import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "用户 APP - 拼团活动") @Tag(name = "用户 APP - 拼团活动")
@ -43,7 +44,7 @@ public class AppCombinationActivityController {
/** /**
* {@link AppCombinationActivityRespVO} 缓存通过它异步刷新 {@link #getCombinationActivityList0(Integer)} 所要的首页数据 * {@link AppCombinationActivityRespVO} 缓存通过它异步刷新 {@link #getCombinationActivityList0(Integer)} 所要的首页数据
*/ */
private final LoadingCache<Integer, List<AppCombinationActivityRespVO>> combinationActivityListCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), private final LoadingCache<Integer, List<AppCombinationActivityRespVO>> combinationActivityListCache = buildCache(Duration.ofSeconds(10L),
new CacheLoader<Integer, List<AppCombinationActivityRespVO>>() { new CacheLoader<Integer, List<AppCombinationActivityRespVO>>() {
@Override @Override

View File

@ -39,6 +39,7 @@ import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildCache;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
@ -52,7 +53,7 @@ public class AppSeckillActivityController {
/** /**
* {@link AppSeckillActivityNowRespVO} 缓存通过它异步刷新 {@link #getNowSeckillActivity()} 所要的首页数据 * {@link AppSeckillActivityNowRespVO} 缓存通过它异步刷新 {@link #getNowSeckillActivity()} 所要的首页数据
*/ */
private final LoadingCache<String, AppSeckillActivityNowRespVO> nowSeckillActivityCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), private final LoadingCache<String, AppSeckillActivityNowRespVO> nowSeckillActivityCache = buildCache(Duration.ofSeconds(10L),
new CacheLoader<String, AppSeckillActivityNowRespVO>() { new CacheLoader<String, AppSeckillActivityNowRespVO>() {
@Override @Override

View File

@ -82,7 +82,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) { public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) {
// 校验验证码 // 校验验证码
String userIp = getClientIP(); String userIp = getClientIP();
smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp)); smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp)).getCheckedData();
// 获得获得注册用户 // 获得获得注册用户
MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp, getTerminal()); MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp, getTerminal());

View File

@ -158,11 +158,11 @@ public class MemberUserServiceImpl implements MemberUserService {
// 补充说明从安全性来说老手机也校验 oldCode 验证码会更安全但是由于 uni-app 商城界面暂时没做所以这里不强制校验 // 补充说明从安全性来说老手机也校验 oldCode 验证码会更安全但是由于 uni-app 商城界面暂时没做所以这里不强制校验
if (StrUtil.isNotEmpty(reqVO.getOldCode())) { if (StrUtil.isNotEmpty(reqVO.getOldCode())) {
smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getOldCode()) smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getOldCode())
.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())); .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())).getCheckedData();
} }
// 2.2 使用新验证码 // 2.2 使用新验证码
smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getMobile()).setCode(reqVO.getCode()) smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getMobile()).setCode(reqVO.getCode())
.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())); .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())).getCheckedData();
// 3. 更新用户手机 // 3. 更新用户手机
memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build()); memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build());
@ -187,7 +187,7 @@ public class MemberUserServiceImpl implements MemberUserService {
MemberUserDO user = validateUserExists(userId); MemberUserDO user = validateUserExists(userId);
// 校验验证码 // 校验验证码
smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getCode()) smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getCode())
.setScene(SmsSceneEnum.MEMBER_UPDATE_PASSWORD.getScene()).setUsedIp(getClientIP())); .setScene(SmsSceneEnum.MEMBER_UPDATE_PASSWORD.getScene()).setUsedIp(getClientIP())).getCheckedData();
// 更新用户密码 // 更新用户密码
memberUserMapper.updateById(MemberUserDO.builder().id(userId) memberUserMapper.updateById(MemberUserDO.builder().id(userId)
@ -201,7 +201,7 @@ public class MemberUserServiceImpl implements MemberUserService {
// 使用验证码 // 使用验证码
smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_RESET_PASSWORD, smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_RESET_PASSWORD,
getClientIP())); getClientIP())).getCheckedData();
// 更新密码 // 更新密码
memberUserMapper.updateById(MemberUserDO.builder().id(user.getId()) memberUserMapper.updateById(MemberUserDO.builder().id(user.getId())

View File

@ -122,7 +122,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override @Override
public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) { public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) {
// 校验验证码 // 校验验证码
smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP())); smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP())).getCheckedData();
// 获得用户信息 // 获得用户信息
AdminUserDO user = userService.getUserByMobile(reqVO.getMobile()); AdminUserDO user = userService.getUserByMobile(reqVO.getMobile());

View File

@ -46,6 +46,7 @@ import java.time.Duration;
import java.util.Objects; import java.util.Objects;
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.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@ -75,7 +76,7 @@ public class SocialClientServiceImpl implements SocialClientService {
* *
* 为什么要做 WxMpService 缓存因为 WxMpService 构建成本比较大所以尽量保证它是单例 * 为什么要做 WxMpService 缓存因为 WxMpService 构建成本比较大所以尽量保证它是单例
*/ */
private final LoadingCache<String, WxMpService> wxMpServiceCache = CacheUtils.buildAsyncReloadingCache( private final LoadingCache<String, WxMpService> wxMpServiceCache = buildAsyncReloadingCache(
Duration.ofSeconds(10L), Duration.ofSeconds(10L),
new CacheLoader<String, WxMpService>() { new CacheLoader<String, WxMpService>() {
@ -96,7 +97,7 @@ public class SocialClientServiceImpl implements SocialClientService {
* *
* 说明同 {@link #wxMpServiceCache} 变量 * 说明同 {@link #wxMpServiceCache} 变量
*/ */
private final LoadingCache<String, WxMaService> wxMaServiceCache = CacheUtils.buildAsyncReloadingCache( private final LoadingCache<String, WxMaService> wxMaServiceCache = buildAsyncReloadingCache(
Duration.ofSeconds(10L), Duration.ofSeconds(10L),
new CacheLoader<String, WxMaService>() { new CacheLoader<String, WxMaService>() {