Selaa lähdekoodia

缓存改造:OAuth2Client 使用 Redis 作为缓存

YunaiV 2 vuotta sitten
vanhempi
commit
7ccdf86d3a
12 muutettua tiedostoa jossa 104 lisäystä ja 240 poistoa
  1. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java
  2. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefine.java
  3. 2 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/MenuMapper.java
  4. 13 13
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java
  5. 0 41
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/common/CaptchaRedisDAO.java
  6. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java
  7. 0 21
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/auth/OAuth2ClientRefreshMessage.java
  8. 0 26
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/auth/OAuth2ClientProducer.java
  9. 10 7
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java
  10. 26 43
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java
  11. 50 58
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImplTest.java
  12. 1 0
      yudao-server/src/main/resources/application.yaml

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java

@@ -26,7 +26,7 @@ public class TenantRedisCacheManager extends TimeoutRedisCacheManager {
      *
      * 原因:如果只补充租户编号,可读性较差
      */
-    private static final String PREFIX = "t";
+    public static final String PREFIX = "t";
 
     private final TenantProperties tenantProperties;
 

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefine.java

@@ -40,7 +40,7 @@ public class TenantRedisKeyDefine extends RedisKeyDefine {
 
     @Override
     public String formatKey(Object... args) {
-        args = ArrayUtil.append(args, TenantContextHolder.getRequiredTenantId());
+        args = ArrayUtil.append(args, TenantRedisCacheManager.PREFIX + TenantContextHolder.getRequiredTenantId());
         return super.formatKey(args);
     }
 

+ 2 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/MenuMapper.java

@@ -4,11 +4,13 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
+import com.baomidou.dynamic.datasource.annotation.Master;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
 
 @Mapper
+@Master
 public interface MenuMapper extends BaseMapperX<MenuDO> {
 
     default MenuDO selectByParentIdAndName(Long parentId, String name) {

+ 13 - 13
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java

@@ -14,23 +14,15 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
  */
 public interface RedisKeyConstants {
 
-    RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("验证码的缓存",
-            "captcha_code:%s", // 参数为 uuid
-            STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
-
     RedisKeyDefine OAUTH2_ACCESS_TOKEN = new RedisKeyDefine("访问令牌的缓存",
             "oauth2_access_token:%s", // 参数为访问令牌 token
             STRING, OAuth2AccessTokenDO.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
 
-    RedisKeyDefine SOCIAL_AUTH_STATE = new RedisKeyDefine("社交登陆的 state", // 注意,它是被 JustAuth 的 justauth.type.prefix 使用到
-            "social_auth_state:%s", // 参数为 state
-            STRING, String.class, Duration.ofHours(24)); // 值为 state
-
     /**
      * 指定部门的所有子部门编号数组的缓存
      *
      * KEY 格式:dept_children_ids::{id}
-     * 数据类型:String 子部门编号集合
+     * VALUE 数据类型:String 子部门编号集合
      */
     String DEPT_CHILDREN_ID_LIST = "dept_children_ids";
 
@@ -38,7 +30,7 @@ public interface RedisKeyConstants {
      * 角色的缓存
      *
      * KEY 格式:role::{id}
-     * 数据类型:String 角色编号
+     * VALUE 数据类型:String 角色信息
      */
     String ROLE = "role";
 
@@ -46,7 +38,7 @@ public interface RedisKeyConstants {
      * 用户拥有的角色编号的缓存
      *
      * KEY 格式:user_role_ids::{userId}
-     * 数据类型:String 角色编号集合
+     * VALUE 数据类型:String 角色编号集合
      */
     String USER_ROLE_ID_LIST = "user_role_ids";
 
@@ -54,7 +46,7 @@ public interface RedisKeyConstants {
      * 拥有指定菜单的角色编号的缓存
      *
      * KEY 格式:user_role_ids::{menuId}
-     * 数据类型:String 角色编号集合
+     * VALUE 数据类型:String 角色编号集合
      */
     String MENU_ROLE_ID_LIST = "menu_role_ids";
 
@@ -62,8 +54,16 @@ public interface RedisKeyConstants {
      * 拥有权限对应的菜单编号数组的缓存
      *
      * KEY 格式:permission_menu_ids::{permission}
-     * 数据类型:String 菜单编号数组
+     * VALUE 数据类型:String 菜单编号数组
      */
     String PERMISSION_MENU_ID_LIST = "permission_menu_ids";
 
+    /**
+     * OAuth2 客户端的缓存
+     *
+     * KEY 格式:user::{id}
+     * VALUE 数据类型:String 客户端信息
+     */
+    String OAUTH_CLIENT = "oauth_client";
+
 }

+ 0 - 41
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/common/CaptchaRedisDAO.java

@@ -1,41 +0,0 @@
-package cn.iocoder.yudao.module.system.dal.redis.common;
-
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.stereotype.Repository;
-
-import javax.annotation.Resource;
-import java.time.Duration;
-
-import static cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants.CAPTCHA_CODE;
-
-/**
- * 验证码的 Redis DAO
- *
- * @author 芋道源码
- */
-@Repository
-public class CaptchaRedisDAO {
-
-    @Resource
-    private StringRedisTemplate stringRedisTemplate;
-
-    public String get(String uuid) {
-        String redisKey = formatKey(uuid);
-        return stringRedisTemplate.opsForValue().get(redisKey);
-    }
-
-    public void set(String uuid, String code, Duration timeout) {
-        String redisKey = formatKey(uuid);
-        stringRedisTemplate.opsForValue().set(redisKey, code, timeout);
-    }
-
-    public void delete(String uuid) {
-        String redisKey = formatKey(uuid);
-        stringRedisTemplate.delete(redisKey);
-    }
-
-    private static String formatKey(String uuid) {
-        return String.format(CAPTCHA_CODE.getKeyTemplate(), uuid);
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.auth;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.auth.OAuth2ClientRefreshMessage;
-import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link OAuth2ClientRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class OAuth2ClientRefreshConsumer extends AbstractChannelMessageListener<OAuth2ClientRefreshMessage> {
-
-    @Resource
-    private OAuth2ClientService oauth2ClientService;
-
-    @Override
-    public void onMessage(OAuth2ClientRefreshMessage message) {
-        log.info("[onMessage][收到 OAuth2Client 刷新消息]");
-        oauth2ClientService.initLocalCache();
-    }
-
-}

+ 0 - 21
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/auth/OAuth2ClientRefreshMessage.java

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.message.auth;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * OAuth 2.0 客户端的数据刷新 Message
- *
- * @author 芋道源码
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class OAuth2ClientRefreshMessage extends AbstractChannelMessage {
-
-    @Override
-    public String getChannel() {
-        return "system.oauth2-client.refresh";
-    }
-
-}

+ 0 - 26
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/auth/OAuth2ClientProducer.java

@@ -1,26 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.producer.auth;
-
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.module.system.mq.message.auth.OAuth2ClientRefreshMessage;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * OAuth 2.0 客户端相关消息的 Producer
- */
-@Component
-public class OAuth2ClientProducer {
-
-    @Resource
-    private RedisMQTemplate redisMQTemplate;
-
-    /**
-     * 发送 {@link OAuth2ClientRefreshMessage} 消息
-     */
-    public void sendOAuth2ClientRefreshMessage() {
-        OAuth2ClientRefreshMessage message = new OAuth2ClientRefreshMessage();
-        redisMQTemplate.send(message);
-    }
-
-}

+ 10 - 7
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java

@@ -18,11 +18,6 @@ import java.util.Collection;
  */
 public interface OAuth2ClientService {
 
-    /**
-     * 初始化 OAuth2Client 的本地缓存
-     */
-    void initLocalCache();
-
     /**
      * 创建 OAuth2 客户端
      *
@@ -53,6 +48,14 @@ public interface OAuth2ClientService {
      */
     OAuth2ClientDO getOAuth2Client(Long id);
 
+    /**
+     * 获得 OAuth2 客户端,从缓存中
+     *
+     * @param clientId 客户端编号
+     * @return OAuth2 客户端
+     */
+    OAuth2ClientDO getOAuth2ClientFromCache(String clientId);
+
     /**
      * 获得 OAuth2 客户端分页
      *
@@ -82,7 +85,7 @@ public interface OAuth2ClientService {
      * @param redirectUri 重定向地址
      * @return 客户端
      */
-    OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret,
-                                             String authorizedGrantType, Collection<String> scopes, String redirectUri);
+    OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType,
+                                             Collection<String> scopes, String redirectUri);
 
 }

+ 26 - 43
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.oauth2;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
@@ -12,22 +13,18 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl
 import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
 import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper;
-import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer;
+import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
 import com.google.common.annotations.VisibleForTesting;
-import lombok.Getter;
-import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import java.util.Collection;
-import java.util.List;
-import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
 
 /**
@@ -40,48 +37,21 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
 @Slf4j
 public class OAuth2ClientServiceImpl implements OAuth2ClientService {
 
-    /**
-     * 客户端缓存
-     * key:客户端编号 {@link OAuth2ClientDO#getClientId()} ()}
-     *
-     * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
-     */
-    @Getter // 解决单测
-    @Setter // 解决单测
-    private volatile Map<String, OAuth2ClientDO> clientCache;
-
     @Resource
     private OAuth2ClientMapper oauth2ClientMapper;
 
-    @Resource
-    private OAuth2ClientProducer oauth2ClientProducer;
-
-    /**
-     * 初始化 {@link #clientCache} 缓存
-     */
-    @Override
-    @PostConstruct
-    public void initLocalCache() {
-        // 第一步:查询数据
-        List<OAuth2ClientDO> clients = oauth2ClientMapper.selectList();
-        log.info("[initLocalCache][缓存 OAuth2 客户端,数量为:{}]", clients.size());
-
-        // 第二步:构建缓存。
-        clientCache = convertMap(clients, OAuth2ClientDO::getClientId);
-    }
-
     @Override
     public Long createOAuth2Client(OAuth2ClientCreateReqVO createReqVO) {
         validateClientIdExists(null, createReqVO.getClientId());
         // 插入
         OAuth2ClientDO oauth2Client = OAuth2ClientConvert.INSTANCE.convert(createReqVO);
         oauth2ClientMapper.insert(oauth2Client);
-        // 发送刷新消息
-        oauth2ClientProducer.sendOAuth2ClientRefreshMessage();
         return oauth2Client.getId();
     }
 
     @Override
+    @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT,
+        allEntries = true) // allEntries 清空所有缓存,因为可能修改到 clientId 字段,不好清理
     public void updateOAuth2Client(OAuth2ClientUpdateReqVO updateReqVO) {
         // 校验存在
         validateOAuth2ClientExists(updateReqVO.getId());
@@ -91,18 +61,16 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
         // 更新
         OAuth2ClientDO updateObj = OAuth2ClientConvert.INSTANCE.convert(updateReqVO);
         oauth2ClientMapper.updateById(updateObj);
-        // 发送刷新消息
-        oauth2ClientProducer.sendOAuth2ClientRefreshMessage();
     }
 
     @Override
+    @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT,
+            allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 key,不好清理
     public void deleteOAuth2Client(Long id) {
         // 校验存在
         validateOAuth2ClientExists(id);
         // 删除
         oauth2ClientMapper.deleteById(id);
-        // 发送刷新消息
-        oauth2ClientProducer.sendOAuth2ClientRefreshMessage();
     }
 
     private void validateOAuth2ClientExists(Long id) {
@@ -131,16 +99,22 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
         return oauth2ClientMapper.selectById(id);
     }
 
+    @Override
+    @Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientId")
+    public OAuth2ClientDO getOAuth2ClientFromCache(String clientId) {
+        return oauth2ClientMapper.selectByClientId(clientId);
+    }
+
     @Override
     public PageResult<OAuth2ClientDO> getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO) {
         return oauth2ClientMapper.selectPage(pageReqVO);
     }
 
     @Override
-    public OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret,
-                                                    String authorizedGrantType, Collection<String> scopes, String redirectUri) {
+    public OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType,
+                                                    Collection<String> scopes, String redirectUri) {
         // 校验客户端存在、且开启
-        OAuth2ClientDO client = clientCache.get(clientId);
+        OAuth2ClientDO client = getSelf().getOAuth2ClientFromCache(clientId);
         if (client == null) {
             throw exception(OAUTH2_CLIENT_NOT_EXISTS);
         }
@@ -167,4 +141,13 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
         return client;
     }
 
+    /**
+     * 获得自身的代理对象,解决 AOP 生效问题
+     *
+     * @return 自己
+     */
+    private OAuth2ClientServiceImpl getSelf() {
+        return SpringUtil.getBean(getClass());
+    }
+
 }

+ 50 - 58
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImplTest.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.system.service.oauth2;
 
-import cn.hutool.core.map.MapUtil;
+import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
@@ -9,14 +9,12 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl
 import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
 import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper;
-import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer;
 import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.mock.mockito.MockBean;
+import org.mockito.MockedStatic;
 import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
 import java.util.Collections;
-import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
@@ -24,7 +22,8 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockStatic;
 
 /**
 * {@link OAuth2ClientServiceImpl} 的单元测试类
@@ -40,26 +39,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
     @Resource
     private OAuth2ClientMapper oauth2ClientMapper;
 
-    @MockBean
-    private OAuth2ClientProducer oauth2ClientProducer;
-
-    @Test
-    public void testInitLocalCache() {
-        // mock 数据
-        OAuth2ClientDO clientDO1 = randomPojo(OAuth2ClientDO.class);
-        oauth2ClientMapper.insert(clientDO1);
-        OAuth2ClientDO clientDO2 = randomPojo(OAuth2ClientDO.class);
-        oauth2ClientMapper.insert(clientDO2);
-
-        // 调用
-        oauth2ClientService.initLocalCache();
-        // 断言 clientCache 缓存
-        Map<String, OAuth2ClientDO> clientCache = oauth2ClientService.getClientCache();
-        assertEquals(2, clientCache.size());
-        assertPojoEquals(clientDO1, clientCache.get(clientDO1.getClientId()));
-        assertPojoEquals(clientDO2, clientCache.get(clientDO2.getClientId()));
-    }
-
     @Test
     public void testCreateOAuth2Client_success() {
         // 准备参数
@@ -73,7 +52,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
         // 校验记录的属性是否正确
         OAuth2ClientDO oAuth2Client = oauth2ClientMapper.selectById(oauth2ClientId);
         assertPojoEquals(reqVO, oAuth2Client);
-        verify(oauth2ClientProducer).sendOAuth2ClientRefreshMessage();
     }
 
     @Test
@@ -92,7 +70,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
         // 校验是否更新正确
         OAuth2ClientDO oAuth2Client = oauth2ClientMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, oAuth2Client);
-        verify(oauth2ClientProducer).sendOAuth2ClientRefreshMessage();
     }
 
     @Test
@@ -116,7 +93,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
         oauth2ClientService.deleteOAuth2Client(id);
         // 校验数据不存在了
         assertNull(oauth2ClientMapper.selectById(id));
-        verify(oauth2ClientProducer).sendOAuth2ClientRefreshMessage();
     }
 
     @Test
@@ -166,6 +142,19 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
         assertPojoEquals(clientDO, dbClientDO);
     }
 
+    @Test
+    public void testGetOAuth2ClientFromCache() {
+        // mock 数据
+        OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class);
+        oauth2ClientMapper.insert(clientDO);
+        // 准备参数
+        String clientId = clientDO.getClientId();
+
+        // 调用,并断言
+        OAuth2ClientDO dbClientDO = oauth2ClientService.getOAuth2ClientFromCache(clientId);
+        assertPojoEquals(clientDO, dbClientDO);
+    }
+
     @Test
     public void testGetOAuth2ClientPage() {
        // mock 数据
@@ -193,36 +182,39 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
 
     @Test
     public void testValidOAuthClientFromCache() {
-        // mock 方法
-        OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("default")
-                .setStatus(CommonStatusEnum.ENABLE.getStatus());
-        OAuth2ClientDO client02 = randomPojo(OAuth2ClientDO.class).setClientId("disable")
-                .setStatus(CommonStatusEnum.DISABLE.getStatus());
-        Map<String, OAuth2ClientDO> clientCache = MapUtil.<String, OAuth2ClientDO>builder()
-                .put(client.getClientId(), client)
-                .put(client02.getClientId(), client02).build();
-        oauth2ClientService.setClientCache(clientCache);
-
-        // 调用,并断言
-        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache(randomString(),
-                null, null, null, null), OAUTH2_CLIENT_NOT_EXISTS);
-        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("disable",
-                null, null, null, null), OAUTH2_CLIENT_DISABLE);
-        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
-                randomString(), null, null, null), OAUTH2_CLIENT_CLIENT_SECRET_ERROR);
-        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
-                null, randomString(), null, null), OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS);
-        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
-                null, null, Collections.singleton(randomString()), null), OAUTH2_CLIENT_SCOPE_OVER);
-        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
-                null, null, null, "test"), OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, "test");
-        // 成功调用(1:参数完整)
-        OAuth2ClientDO result = oauth2ClientService.validOAuthClientFromCache(client.getClientId(), client.getSecret(),
-                client.getAuthorizedGrantTypes().get(0), client.getScopes(), client.getRedirectUris().get(0));
-        assertPojoEquals(client, result);
-        // 成功调用(2:只有 clientId 参数)
-        result = oauth2ClientService.validOAuthClientFromCache(client.getClientId());
-        assertPojoEquals(client, result);
+        try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+            springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(OAuth2ClientServiceImpl.class)))
+                    .thenReturn(oauth2ClientService);
+
+            // mock 方法
+            OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("default")
+                    .setStatus(CommonStatusEnum.ENABLE.getStatus());
+            oauth2ClientMapper.insert(client);
+            OAuth2ClientDO client02 = randomPojo(OAuth2ClientDO.class).setClientId("disable")
+                    .setStatus(CommonStatusEnum.DISABLE.getStatus());
+            oauth2ClientMapper.insert(client02);
+
+            // 调用,并断言
+            assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache(randomString(),
+                    null, null, null, null), OAUTH2_CLIENT_NOT_EXISTS);
+            assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("disable",
+                    null, null, null, null), OAUTH2_CLIENT_DISABLE);
+            assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                    randomString(), null, null, null), OAUTH2_CLIENT_CLIENT_SECRET_ERROR);
+            assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                    null, randomString(), null, null), OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS);
+            assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                    null, null, Collections.singleton(randomString()), null), OAUTH2_CLIENT_SCOPE_OVER);
+            assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                    null, null, null, "test"), OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, "test");
+            // 成功调用(1:参数完整)
+            OAuth2ClientDO result = oauth2ClientService.validOAuthClientFromCache(client.getClientId(), client.getSecret(),
+                    client.getAuthorizedGrantTypes().get(0), client.getScopes(), client.getRedirectUris().get(0));
+            assertPojoEquals(client, result);
+            // 成功调用(2:只有 clientId 参数)
+            result = oauth2ClientService.validOAuthClientFromCache(client.getClientId());
+            assertPojoEquals(client, result);
+        }
     }
 
 }

+ 1 - 0
yudao-server/src/main/resources/application.yaml

@@ -191,6 +191,7 @@ yudao:
       - tmp_report_data_income
     ignore-caches:
       - permission_menu_ids
+      - oauth_client
   sms-code: # 短信验证码相关的配置项
     expire-times: 10m
     send-frequency: 1m