Merge branch 'master-jdk21' of https://gitee.com/zhijiantianya/yudao-cloud
						commit
						5517dc7d4a
					
				| 
						 | 
				
			
			@ -1,12 +1,10 @@
 | 
			
		|||
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.CacheLoader;
 | 
			
		||||
import com.google.common.cache.LoadingCache;
 | 
			
		||||
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
import java.util.concurrent.Executor;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -16,14 +14,36 @@ import java.util.concurrent.Executors;
 | 
			
		|||
 */
 | 
			
		||||
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) {
 | 
			
		||||
        Executor executor = Executors.newCachedThreadPool(  // TODO 芋艿:可能要思考下,未来要不要做成可配置
 | 
			
		||||
                TtlExecutors.getDefaultDisableInheritableThreadFactory()); // TTL 保证 ThreadLocal 可以透传
 | 
			
		||||
        return CacheBuilder.newBuilder()
 | 
			
		||||
                // 只阻塞当前数据加载线程,其他线程返回旧值
 | 
			
		||||
                .refreshAfterWrite(duration)
 | 
			
		||||
                // 通过 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,8 @@ import lombok.extern.slf4j.Slf4j;
 | 
			
		|||
 | 
			
		||||
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)} 的缓存
 | 
			
		||||
     */
 | 
			
		||||
    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 分钟
 | 
			
		||||
            new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +44,7 @@ public class DictFrameworkUtils {
 | 
			
		|||
    /**
 | 
			
		||||
     * 针对 {@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 分钟
 | 
			
		||||
            new CacheLoader<KeyValue<String, String>, DictDataRespDTO>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@ import lombok.SneakyThrows;
 | 
			
		|||
import java.time.Duration;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tenant 框架 Service 实现类
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +26,7 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
 | 
			
		|||
    /**
 | 
			
		||||
     * 针对 {@link #getTenantIds()} 的缓存
 | 
			
		||||
     */
 | 
			
		||||
    private final LoadingCache<Object, List<Long>> getTenantIdsCache = CacheUtils.buildAsyncReloadingCache(
 | 
			
		||||
    private final LoadingCache<Object, List<Long>> getTenantIdsCache = buildAsyncReloadingCache(
 | 
			
		||||
            Duration.ofMinutes(1L), // 过期时间 1 分钟
 | 
			
		||||
            new CacheLoader<Object, List<Long>>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +40,7 @@ public class TenantFrameworkServiceImpl implements TenantFrameworkService {
 | 
			
		|||
    /**
 | 
			
		||||
     * 针对 {@link #validTenant(Long)} 的缓存
 | 
			
		||||
     */
 | 
			
		||||
    private final LoadingCache<Long, CommonResult<Boolean>> validTenantCache = CacheUtils.buildAsyncReloadingCache(
 | 
			
		||||
    private final LoadingCache<Long, CommonResult<Boolean>> validTenantCache = buildAsyncReloadingCache(
 | 
			
		||||
            Duration.ofMinutes(1L), // 过期时间 1 分钟
 | 
			
		||||
            new CacheLoader<Long, CommonResult<Boolean>>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,8 @@ import java.time.Duration;
 | 
			
		|||
import java.util.Arrays;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +37,7 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
 | 
			
		|||
    /**
 | 
			
		||||
     * 针对 {@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 分钟
 | 
			
		||||
            new CacheLoader<KeyValue<Long, List<String>>, Boolean>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +51,7 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
 | 
			
		|||
    /**
 | 
			
		||||
     * 针对 {@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 分钟
 | 
			
		||||
            new CacheLoader<KeyValue<Long, List<String>>, Boolean>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,9 @@ import java.time.Duration;
 | 
			
		|||
import java.util.Objects;
 | 
			
		||||
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 的有效性
 | 
			
		||||
 * 1. 验证通过时,将 userId、userType、tenantId 通过 Header 转发给服务
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +62,7 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered {
 | 
			
		|||
     * key1:多租户的编号
 | 
			
		||||
     * 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>() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.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;
 | 
			
		||||
 | 
			
		||||
@Tag(name = "用户 App - 砍价活动")
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +43,7 @@ public class AppBargainActivityController {
 | 
			
		|||
    /**
 | 
			
		||||
     * {@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>>() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.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;
 | 
			
		||||
 | 
			
		||||
@Tag(name = "用户 APP - 拼团活动")
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +44,7 @@ public class AppCombinationActivityController {
 | 
			
		|||
    /**
 | 
			
		||||
     * {@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>>() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.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.findFirst;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +53,7 @@ public class AppSeckillActivityController {
 | 
			
		|||
    /**
 | 
			
		||||
     * {@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>() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,7 +82,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
 | 
			
		|||
    public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) {
 | 
			
		||||
        // 校验验证码
 | 
			
		||||
        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());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,11 +158,11 @@ public class MemberUserServiceImpl implements MemberUserService {
 | 
			
		|||
        // 补充说明:从安全性来说,老手机也校验 oldCode 验证码会更安全。但是由于 uni-app 商城界面暂时没做,所以这里不强制校验
 | 
			
		||||
        if (StrUtil.isNotEmpty(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 使用新验证码
 | 
			
		||||
        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. 更新用户手机
 | 
			
		||||
        memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build());
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ public class MemberUserServiceImpl implements MemberUserService {
 | 
			
		|||
        MemberUserDO user = validateUserExists(userId);
 | 
			
		||||
        // 校验验证码
 | 
			
		||||
        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)
 | 
			
		||||
| 
						 | 
				
			
			@ -201,7 +201,7 @@ public class MemberUserServiceImpl implements MemberUserService {
 | 
			
		|||
 | 
			
		||||
        // 使用验证码
 | 
			
		||||
        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_RESET_PASSWORD,
 | 
			
		||||
                getClientIP()));
 | 
			
		||||
                getClientIP())).getCheckedData();
 | 
			
		||||
 | 
			
		||||
        // 更新密码
 | 
			
		||||
        memberUserMapper.updateById(MemberUserDO.builder().id(user.getId())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		|||
    @Override
 | 
			
		||||
    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());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ import java.time.Duration;
 | 
			
		|||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
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.module.system.enums.ErrorCodeConstants.*;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +76,7 @@ public class SocialClientServiceImpl implements SocialClientService {
 | 
			
		|||
     *
 | 
			
		||||
     * 为什么要做 WxMpService 缓存?因为 WxMpService 构建成本比较大,所以尽量保证它是单例。
 | 
			
		||||
     */
 | 
			
		||||
    private final LoadingCache<String, WxMpService> wxMpServiceCache = CacheUtils.buildAsyncReloadingCache(
 | 
			
		||||
    private final LoadingCache<String, WxMpService> wxMpServiceCache = buildAsyncReloadingCache(
 | 
			
		||||
            Duration.ofSeconds(10L),
 | 
			
		||||
            new CacheLoader<String, WxMpService>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +97,7 @@ public class SocialClientServiceImpl implements SocialClientService {
 | 
			
		|||
     *
 | 
			
		||||
     * 说明同 {@link #wxMpServiceCache} 变量
 | 
			
		||||
     */
 | 
			
		||||
    private final LoadingCache<String, WxMaService> wxMaServiceCache = CacheUtils.buildAsyncReloadingCache(
 | 
			
		||||
    private final LoadingCache<String, WxMaService> wxMaServiceCache = buildAsyncReloadingCache(
 | 
			
		||||
            Duration.ofSeconds(10L),
 | 
			
		||||
            new CacheLoader<String, WxMaService>() {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue