Commit 79a0b4cb56b323cbf202621e10c34c73963eb1de
1 parent
7bd81d03
增加菜单的定时刷新
Showing
8 changed files
with
76 additions
and
19 deletions
ruoyi-quartz/pom.xml
| ... | ... | @@ -28,13 +28,6 @@ |
| 28 | 28 | </exclusion> |
| 29 | 29 | </exclusions> |
| 30 | 30 | </dependency> |
| 31 | - | |
| 32 | - <!-- 通用工具--> | |
| 33 | - <dependency> | |
| 34 | - <groupId>com.ruoyi</groupId> | |
| 35 | - <artifactId>ruoyi-common</artifactId> | |
| 36 | - </dependency> | |
| 37 | - | |
| 38 | 31 | </dependencies> |
| 39 | 32 | |
| 40 | -</project> | |
| 41 | 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 | 73 | if (CollUtil.isEmpty(configs)) { // 如果没有更新,则返回 |
| 74 | 74 | return; |
| 75 | 75 | } |
| 76 | - log.info("[sync][同步到新配置,配置数量为:{}]", configs.size()); | |
| 77 | 76 | |
| 78 | 77 | // 第二步,构建新的 Properties |
| 79 | 78 | Properties newProperties = this.buildProperties(configs); |
| ... | ... | @@ -83,6 +82,7 @@ public class DBConfigRepository extends AbstractConfigRepository { |
| 83 | 82 | this.maxUpdateTime = configs.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); |
| 84 | 83 | // 第四部,触发配置刷新!重要!!!! |
| 85 | 84 | super.fireRepositoryChange(m_namespace, newProperties); |
| 85 | + log.info("[sync][缓存配置,数量为:{}]", configs.size()); | |
| 86 | 86 | } |
| 87 | 87 | |
| 88 | 88 | @Override |
| ... | ... | @@ -150,7 +150,7 @@ public class DBConfigRepository extends AbstractConfigRepository { |
| 150 | 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
| 1 | +package cn.iocoder.dashboard.framework.quartz.config; | |
| 2 | + | |
| 3 | +import org.springframework.context.annotation.Configuration; | |
| 4 | +import org.springframework.scheduling.annotation.EnableScheduling; | |
| 5 | + | |
| 6 | +@Configuration | |
| 7 | +@EnableScheduling // 开启 Spring 自带的定时任务 | |
| 8 | +public class QuartzConfig { | |
| 9 | +} | ... | ... |
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 | 32 | } |
| 33 | 33 | |
| 34 | 34 | @Override |
| 35 | - public List<InfConfigDO> getSysConfigList() { | |
| 35 | + public List<InfConfigDO> selectList() { | |
| 36 | 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 | 7 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | |
| 10 | +import java.util.Date; | |
| 10 | 11 | import java.util.List; |
| 11 | 12 | |
| 12 | 13 | @Mapper |
| ... | ... | @@ -30,4 +31,9 @@ public interface SysMenuMapper extends BaseMapper<SysMenuDO> { |
| 30 | 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 | 1 | package cn.iocoder.dashboard.modules.system.service.permission.impl; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; |
| 5 | +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | |
| 4 | 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuCreateReqVO; |
| 5 | 7 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuListReqVO; |
| 6 | 8 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuUpdateReqVO; |
| ... | ... | @@ -16,14 +18,12 @@ import com.google.common.collect.ImmutableMap; |
| 16 | 18 | import com.google.common.collect.ImmutableMultimap; |
| 17 | 19 | import com.google.common.collect.Multimap; |
| 18 | 20 | import lombok.extern.slf4j.Slf4j; |
| 21 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 19 | 22 | import org.springframework.stereotype.Service; |
| 20 | 23 | |
| 21 | 24 | import javax.annotation.PostConstruct; |
| 22 | 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 | 27 | import java.util.stream.Collectors; |
| 28 | 28 | |
| 29 | 29 | import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; |
| ... | ... | @@ -38,6 +38,12 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; |
| 38 | 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 | 48 | * key:菜单编号 |
| 43 | 49 | * |
| ... | ... | @@ -52,6 +58,10 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 52 | 58 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 |
| 53 | 59 | */ |
| 54 | 60 | private volatile Multimap<String, SysMenuDO> permMenuCache; |
| 61 | + /** | |
| 62 | + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | |
| 63 | + */ | |
| 64 | + private volatile Date maxUpdateTime; | |
| 55 | 65 | |
| 56 | 66 | @Resource |
| 57 | 67 | private SysMenuMapper menuMapper; |
| ... | ... | @@ -63,8 +73,14 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 63 | 73 | */ |
| 64 | 74 | @Override |
| 65 | 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 | 84 | ImmutableMap.Builder<Long, SysMenuDO> menuCacheBuilder = ImmutableMap.builder(); |
| 69 | 85 | ImmutableMultimap.Builder<String, SysMenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); |
| 70 | 86 | menuList.forEach(menuDO -> { |
| ... | ... | @@ -73,7 +89,35 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 73 | 89 | }); |
| 74 | 90 | menuCache = menuCacheBuilder.build(); |
| 75 | 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 | 123 | @Override | ... | ... |