Browse Source

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

YunaiV 2 years ago
parent
commit
dfb1bdb9fb

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

@@ -25,4 +25,7 @@ public interface MenuMapper extends BaseMapperX<MenuDO> {
                 .eqIfPresent(MenuDO::getStatus, reqVO.getStatus()));
     }
 
+    default List<MenuDO> selectListByPermission(String permission) {
+        return selectList(MenuDO::getPermission, permission);
+    }
 }

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

@@ -62,4 +62,12 @@ public interface RedisKeyConstants {
      */
     String DEPT_CHILDREN_ID_LIST_EXPIRE = "30s";
 
+    /**
+     * 拥有权限对应的菜单编号数组的缓存
+     *
+     * KEY 格式:permission_menu_ids::{permission}
+     * 数据类型:String 菜单编号数组
+     */
+    String PERMISSION_MENU_ID_LIST = "permission_menu_ids";
+
 }

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

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

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

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.message.permission;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * 菜单数据刷新 Message
- *
- * @author 芋道源码
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class MenuRefreshMessage extends AbstractChannelMessage {
-
-    @Override
-    public String getChannel() {
-        return "system.menu.refresh";
-    }
-
-}

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

@@ -1,26 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.producer.permission;
-
-import cn.iocoder.yudao.module.system.mq.message.permission.MenuRefreshMessage;
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * Menu 菜单相关消息的 Producer
- */
-@Component
-public class MenuProducer {
-
-    @Resource
-    private RedisMQTemplate redisMQTemplate;
-
-    /**
-     * 发送 {@link MenuRefreshMessage} 消息
-     */
-    public void sendMenuRefreshMessage() {
-        MenuRefreshMessage message = new MenuRefreshMessage();
-        redisMQTemplate.send(message);
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java

@@ -15,11 +15,6 @@ import java.util.List;
  */
 public interface MenuService {
 
-    /**
-     * 初始化菜单的本地缓存
-     */
-    void initLocalCache();
-
     /**
      * 创建菜单
      *
@@ -66,30 +61,6 @@ public interface MenuService {
      */
     List<MenuDO> getMenuList(MenuListReqVO reqVO);
 
-    /**
-     * 获得所有菜单,从缓存中
-     *
-     * 任一参数为空时,则返回为空
-     *
-     * @param menuTypes 菜单类型数组
-     * @param menusStatuses 菜单状态数组
-     * @return 菜单列表
-     */
-    List<MenuDO> getMenuListFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses);
-
-    /**
-     * 获得指定编号的菜单数组,从缓存中
-     *
-     * 任一参数为空时,则返回为空
-     *
-     * @param menuIds 菜单编号数组
-     * @param menuTypes 菜单类型数组
-     * @param menusStatuses 菜单状态数组
-     * @return 菜单数组
-     */
-    List<MenuDO> getMenuListFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes,
-                                      Collection<Integer> menusStatuses);
-
     /**
      * 获得权限对应的菜单数组
      *

+ 6 - 98
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java

@@ -1,34 +1,25 @@
 package cn.iocoder.yudao.module.system.service.permission;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUpdateReqVO;
 import cn.iocoder.yudao.module.system.convert.permission.MenuConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
 import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper;
+import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
 import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
-import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer;
 import cn.iocoder.yudao.module.system.service.tenant.TenantService;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Multimap;
-import lombok.Getter;
-import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.transaction.support.TransactionSynchronization;
-import org.springframework.transaction.support.TransactionSynchronizationManager;
 
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
-import java.util.*;
-import java.util.stream.Collectors;
+import java.util.Collection;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT;
@@ -43,26 +34,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
 @Slf4j
 public class MenuServiceImpl implements MenuService {
 
-    /**
-     * 菜单缓存
-     * key:菜单编号
-     *
-     * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
-     */
-    @Getter
-    @Setter
-    private volatile Map<Long, MenuDO> menuCache;
-    /**
-     * 权限与菜单缓存
-     * key:权限 {@link MenuDO#getPermission()}
-     * value:MenuDO 数组,因为一个权限可能对应多个 MenuDO 对象
-     *
-     * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
-     */
-    @Getter
-    @Setter
-    private volatile Multimap<String, MenuDO> permissionMenuCache;
-
     @Resource
     private MenuMapper menuMapper;
     @Resource
@@ -71,32 +42,6 @@ public class MenuServiceImpl implements MenuService {
     @Lazy // 延迟,避免循环依赖报错
     private TenantService tenantService;
 
-    @Resource
-    private MenuProducer menuProducer;
-
-    /**
-     * 初始化 {@link #menuCache} 和 {@link #permissionMenuCache} 缓存
-     */
-    @Override
-    @PostConstruct
-    public synchronized void initLocalCache() {
-        // 第一步:查询数据
-        List<MenuDO> menuList = menuMapper.selectList();
-        log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size());
-
-        // 第二步:构建缓存
-        ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder();
-        ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder();
-        menuList.forEach(menuDO -> {
-            menuCacheBuilder.put(menuDO.getId(), menuDO);
-            if (StrUtil.isNotEmpty(menuDO.getPermission())) { // 会存在 permission 为 null 的情况,导致 put 报 NPE 异常
-                permMenuCacheBuilder.put(menuDO.getPermission(), menuDO);
-            }
-        });
-        menuCache = menuCacheBuilder.build();
-        permissionMenuCache = permMenuCacheBuilder.build();
-    }
-
     @Override
     public Long createMenu(MenuCreateReqVO reqVO) {
         // 校验父菜单存在
@@ -108,8 +53,6 @@ public class MenuServiceImpl implements MenuService {
         MenuDO menu = MenuConvert.INSTANCE.convert(reqVO);
         initMenuProperty(menu);
         menuMapper.insert(menu);
-        // 发送刷新消息
-        menuProducer.sendMenuRefreshMessage();
         // 返回
         return menu.getId();
     }
@@ -129,8 +72,6 @@ public class MenuServiceImpl implements MenuService {
         MenuDO updateObject = MenuConvert.INSTANCE.convert(reqVO);
         initMenuProperty(updateObject);
         menuMapper.updateById(updateObject);
-        // 发送刷新消息
-        menuProducer.sendMenuRefreshMessage();
     }
 
     @Override
@@ -148,15 +89,6 @@ public class MenuServiceImpl implements MenuService {
         menuMapper.deleteById(menuId);
         // 删除授予给角色的权限
         permissionService.processMenuDeleted(menuId);
-        // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了
-        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
-
-            @Override
-            public void afterCommit() {
-                menuProducer.sendMenuRefreshMessage();
-            }
-
-        });
     }
 
     @Override
@@ -178,33 +110,9 @@ public class MenuServiceImpl implements MenuService {
     }
 
     @Override
-    public List<MenuDO> getMenuListFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses) {
-        // 任一一个参数为空,则返回空
-        if (CollectionUtils.isAnyEmpty(menuTypes, menusStatuses)) {
-            return Collections.emptyList();
-        }
-        // 创建新数组,避免缓存被修改
-        return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getType())
-                && menusStatuses.contains(menu.getStatus()))
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public List<MenuDO> getMenuListFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes,
-                                             Collection<Integer> menusStatuses) {
-        // 任一一个参数为空,则返回空
-        if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) {
-            return Collections.emptyList();
-        }
-        return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getId())
-                && menuTypes.contains(menu.getType())
-                && menusStatuses.contains(menu.getStatus()))
-                .collect(Collectors.toList());
-    }
-
-    @Override
+    @Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission")
     public List<MenuDO> getMenuListByPermissionFromCache(String permission) {
-        return new ArrayList<>(permissionMenuCache.get(permission));
+        return menuMapper.selectListByPermission(permission);
     }
 
     @Override

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

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