Commit 79a0b4cb56b323cbf202621e10c34c73963eb1de
1 parent
7bd81d03
增加菜单的定时刷新
Showing
8 changed files
with
76 additions
and
19 deletions
ruoyi-quartz/pom.xml
| @@ -28,13 +28,6 @@ | @@ -28,13 +28,6 @@ | ||
| 28 | </exclusion> | 28 | </exclusion> |
| 29 | </exclusions> | 29 | </exclusions> |
| 30 | </dependency> | 30 | </dependency> |
| 31 | - | ||
| 32 | - <!-- 通用工具--> | ||
| 33 | - <dependency> | ||
| 34 | - <groupId>com.ruoyi</groupId> | ||
| 35 | - <artifactId>ruoyi-common</artifactId> | ||
| 36 | - </dependency> | ||
| 37 | - | ||
| 38 | </dependencies> | 31 | </dependencies> |
| 39 | 32 | ||
| 40 | -</project> | ||
| 41 | \ No newline at end of file | 33 | \ No newline at end of file |
| 34 | +</project> |
src/main/java/cn/iocoder/dashboard/framework/apollo/internals/ConfigFrameworkDAO.java
src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java
| @@ -73,7 +73,6 @@ public class DBConfigRepository extends AbstractConfigRepository { | @@ -73,7 +73,6 @@ public class DBConfigRepository extends AbstractConfigRepository { | ||
| 73 | if (CollUtil.isEmpty(configs)) { // 如果没有更新,则返回 | 73 | if (CollUtil.isEmpty(configs)) { // 如果没有更新,则返回 |
| 74 | return; | 74 | return; |
| 75 | } | 75 | } |
| 76 | - log.info("[sync][同步到新配置,配置数量为:{}]", configs.size()); | ||
| 77 | 76 | ||
| 78 | // 第二步,构建新的 Properties | 77 | // 第二步,构建新的 Properties |
| 79 | Properties newProperties = this.buildProperties(configs); | 78 | Properties newProperties = this.buildProperties(configs); |
| @@ -83,6 +82,7 @@ public class DBConfigRepository extends AbstractConfigRepository { | @@ -83,6 +82,7 @@ public class DBConfigRepository extends AbstractConfigRepository { | ||
| 83 | this.maxUpdateTime = configs.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | 82 | this.maxUpdateTime = configs.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); |
| 84 | // 第四部,触发配置刷新!重要!!!! | 83 | // 第四部,触发配置刷新!重要!!!! |
| 85 | super.fireRepositoryChange(m_namespace, newProperties); | 84 | super.fireRepositoryChange(m_namespace, newProperties); |
| 85 | + log.info("[sync][缓存配置,数量为:{}]", configs.size()); | ||
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | @Override | 88 | @Override |
| @@ -150,7 +150,7 @@ public class DBConfigRepository extends AbstractConfigRepository { | @@ -150,7 +150,7 @@ public class DBConfigRepository extends AbstractConfigRepository { | ||
| 150 | log.info("[loadConfigIfUpdate][增量加载全量配置]"); | 150 | log.info("[loadConfigIfUpdate][增量加载全量配置]"); |
| 151 | } | 151 | } |
| 152 | // 第二步,如果有更新,则从数据库加载所有配置 | 152 | // 第二步,如果有更新,则从数据库加载所有配置 |
| 153 | - return configFrameworkDAO.getSysConfigList(); | 153 | + return configFrameworkDAO.selectList(); |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | } | 156 | } |
src/main/java/cn/iocoder/dashboard/framework/quartz/config/QuartzConfig.java
0 → 100644
src/main/java/cn/iocoder/dashboard/framework/quartz/package-info.java
0 → 100644
src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/dao/config/InfConfigDAOImpl.java
| @@ -32,7 +32,7 @@ public class InfConfigDAOImpl implements ConfigFrameworkDAO { | @@ -32,7 +32,7 @@ public class InfConfigDAOImpl implements ConfigFrameworkDAO { | ||
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | @Override | 34 | @Override |
| 35 | - public List<InfConfigDO> getSysConfigList() { | 35 | + public List<InfConfigDO> selectList() { |
| 36 | return jdbcTemplate.query("SELECT `key`, `value`, update_time, deleted FROM inf_config", new BeanPropertyRowMapper<>(InfConfigDO.class)); | 36 | return jdbcTemplate.query("SELECT `key`, `value`, update_time, deleted FROM inf_config", new BeanPropertyRowMapper<>(InfConfigDO.class)); |
| 37 | } | 37 | } |
| 38 | 38 |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/permission/SysMenuMapper.java
| @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 7 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | 7 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| 8 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | ||
| 10 | +import java.util.Date; | ||
| 10 | import java.util.List; | 11 | import java.util.List; |
| 11 | 12 | ||
| 12 | @Mapper | 13 | @Mapper |
| @@ -30,4 +31,9 @@ public interface SysMenuMapper extends BaseMapper<SysMenuDO> { | @@ -30,4 +31,9 @@ public interface SysMenuMapper extends BaseMapper<SysMenuDO> { | ||
| 30 | return selectList(new QueryWrapper<>()); | 31 | return selectList(new QueryWrapper<>()); |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 34 | + default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) { | ||
| 35 | + return selectOne(new QueryWrapper<SysMenuDO>().select("id") | ||
| 36 | + .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null; | ||
| 37 | + } | ||
| 38 | + | ||
| 33 | } | 39 | } |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java
| 1 | package cn.iocoder.dashboard.modules.system.service.permission.impl; | 1 | package cn.iocoder.dashboard.modules.system.service.permission.impl; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; | 4 | import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; |
| 5 | +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuCreateReqVO; | 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuCreateReqVO; |
| 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuListReqVO; | 7 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuListReqVO; |
| 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuUpdateReqVO; | 8 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuUpdateReqVO; |
| @@ -16,14 +18,12 @@ import com.google.common.collect.ImmutableMap; | @@ -16,14 +18,12 @@ import com.google.common.collect.ImmutableMap; | ||
| 16 | import com.google.common.collect.ImmutableMultimap; | 18 | import com.google.common.collect.ImmutableMultimap; |
| 17 | import com.google.common.collect.Multimap; | 19 | import com.google.common.collect.Multimap; |
| 18 | import lombok.extern.slf4j.Slf4j; | 20 | import lombok.extern.slf4j.Slf4j; |
| 21 | +import org.springframework.scheduling.annotation.Scheduled; | ||
| 19 | import org.springframework.stereotype.Service; | 22 | import org.springframework.stereotype.Service; |
| 20 | 23 | ||
| 21 | import javax.annotation.PostConstruct; | 24 | import javax.annotation.PostConstruct; |
| 22 | import javax.annotation.Resource; | 25 | import javax.annotation.Resource; |
| 23 | -import java.util.Collection; | ||
| 24 | -import java.util.Collections; | ||
| 25 | -import java.util.List; | ||
| 26 | -import java.util.Map; | 26 | +import java.util.*; |
| 27 | import java.util.stream.Collectors; | 27 | import java.util.stream.Collectors; |
| 28 | 28 | ||
| 29 | import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | 29 | import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; |
| @@ -38,6 +38,12 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | @@ -38,6 +38,12 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | ||
| 38 | public class SysMenuServiceImpl implements SysMenuService { | 38 | public class SysMenuServiceImpl implements SysMenuService { |
| 39 | 39 | ||
| 40 | /** | 40 | /** |
| 41 | + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 | ||
| 42 | + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 | ||
| 43 | + */ | ||
| 44 | + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | ||
| 45 | + | ||
| 46 | + /** | ||
| 41 | * 菜单缓存 | 47 | * 菜单缓存 |
| 42 | * key:菜单编号 | 48 | * key:菜单编号 |
| 43 | * | 49 | * |
| @@ -52,6 +58,10 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -52,6 +58,10 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 52 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | 58 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 |
| 53 | */ | 59 | */ |
| 54 | private volatile Multimap<String, SysMenuDO> permMenuCache; | 60 | private volatile Multimap<String, SysMenuDO> permMenuCache; |
| 61 | + /** | ||
| 62 | + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | ||
| 63 | + */ | ||
| 64 | + private volatile Date maxUpdateTime; | ||
| 55 | 65 | ||
| 56 | @Resource | 66 | @Resource |
| 57 | private SysMenuMapper menuMapper; | 67 | private SysMenuMapper menuMapper; |
| @@ -63,8 +73,14 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -63,8 +73,14 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 63 | */ | 73 | */ |
| 64 | @Override | 74 | @Override |
| 65 | @PostConstruct | 75 | @PostConstruct |
| 66 | - public void init() { | ||
| 67 | - List<SysMenuDO> menuList = menuMapper.selectList(); | 76 | + public synchronized void init() { |
| 77 | + // 获取 | ||
| 78 | + List<SysMenuDO> menuList = this.loadMenuIfUpdate(maxUpdateTime); | ||
| 79 | + if (CollUtil.isEmpty(menuList)) { | ||
| 80 | + return; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + // 构建缓存 | ||
| 68 | ImmutableMap.Builder<Long, SysMenuDO> menuCacheBuilder = ImmutableMap.builder(); | 84 | ImmutableMap.Builder<Long, SysMenuDO> menuCacheBuilder = ImmutableMap.builder(); |
| 69 | ImmutableMultimap.Builder<String, SysMenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); | 85 | ImmutableMultimap.Builder<String, SysMenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); |
| 70 | menuList.forEach(menuDO -> { | 86 | menuList.forEach(menuDO -> { |
| @@ -73,7 +89,35 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -73,7 +89,35 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 73 | }); | 89 | }); |
| 74 | menuCache = menuCacheBuilder.build(); | 90 | menuCache = menuCacheBuilder.build(); |
| 75 | permMenuCache = permMenuCacheBuilder.build(); | 91 | permMenuCache = permMenuCacheBuilder.build(); |
| 76 | - log.info("[init][初始化菜单数量为 {}]", menuList.size()); | 92 | + assert menuList.size() > 0; // 断言,避免告警 |
| 93 | + maxUpdateTime = menuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | ||
| 94 | + log.info("[init][缓存菜单,数量为:{}]", menuList.size()); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | ||
| 98 | + public void schedulePeriodicRefresh() { | ||
| 99 | + init(); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * 如果菜单发生变化,从数据库中获取最新的全量菜单。 | ||
| 104 | + * 如果未发生变化,则返回空 | ||
| 105 | + * | ||
| 106 | + * @param maxUpdateTime 当前菜单的最大更新时间 | ||
| 107 | + * @return 菜单列表 | ||
| 108 | + */ | ||
| 109 | + private List<SysMenuDO> loadMenuIfUpdate(Date maxUpdateTime) { | ||
| 110 | + // 第一步,判断是否要更新。 | ||
| 111 | + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 | ||
| 112 | + log.info("[loadMenuIfUpdate][首次加载全量菜单]"); | ||
| 113 | + } else { // 判断数据库中是否有更新的菜单 | ||
| 114 | + if (!menuMapper.selectExistsByUpdateTimeAfter(maxUpdateTime)) { | ||
| 115 | + return null; | ||
| 116 | + } | ||
| 117 | + log.info("[loadMenuIfUpdate][增量加载全量菜单]"); | ||
| 118 | + } | ||
| 119 | + // 第二步,如果有更新,则从数据库加载所有菜单 | ||
| 120 | + return menuMapper.selectList(); | ||
| 77 | } | 121 | } |
| 78 | 122 | ||
| 79 | @Override | 123 | @Override |