refactor(cache): 缓存操作接口化,支持 Redis/Caffeine 双实现切换

将系统所有缓存操作从 `RedisUtil` 迁移至 `CacheOperations` 接口,
通过 `gym.cache.type` 配置选择 Redis 或 Caffeine 实现。

变更内容:
- 新增 CacheOperations 接口,定义 get/set/delete/hasKey/expire/deleteByPattern 等标准方法
- 新增 RedisCacheOperations 实现(基于 ReactiveRedisTemplate,默认实现)
- 新增 CaffeineCacheOperations 实现(基于 Caffeine 本地缓存)
- 新增 CacheProperties 配置类,支持 Caffeine 容量/过期等参数配置
- 新增 CacheAutoConfiguration 自动装配,通过 AutoConfiguration.imports 注册
- 全系统 17 个业务服务 + 18 个测试文件从 RedisUtil 迁移至 CacheOperations
- manage-gateway 配置 caffeine 实现(无需 Redis),manage-app 配置 redis 实现
- 分布式锁等 Redis 独有特性保持直接使用 ReactiveRedisTemplate

测试:202 通过,0 失败,0 错误
This commit was merged in pull request #56.
This commit is contained in:
2026-08-02 18:26:15 +08:00
parent eb33755f23
commit 4ba4af2f53
45 changed files with 798 additions and 476 deletions
@@ -1,5 +1,6 @@
package cn.novalon.gym.manage.datacount.scheduler;
import cn.novalon.gym.manage.common.cache.CacheOperations;
import cn.novalon.gym.manage.datacount.domain.DataStatistics;
import cn.novalon.gym.manage.datacount.service.IDataStatisticsService;
import org.slf4j.Logger;
@@ -98,7 +99,7 @@ public class DataStatisticsScheduler {
// 清理Redis中的旧统计数据
String pattern = "datacount:statistics:*:" + cutoffDate.toString();
cn.novalon.gym.manage.common.util.RedisUtil redisUtil = null;
CacheOperations cacheOperations = null;
try {
// 这里可以通过注入的service来清理,但当前实现使用Redis缓存30天自动过期
log.info("Old statistics cleanup completed, cutoff date: {}", cutoffDate);
@@ -1,7 +1,7 @@
package cn.novalon.gym.manage.datacount.service.impl;
import cn.novalon.gym.manage.checkIn.entity.SignInRecord;
import cn.novalon.gym.manage.common.util.RedisUtil;
import cn.novalon.gym.manage.common.cache.CacheOperations;
import cn.novalon.gym.manage.datacount.dao.DataStatisticsDao;
import cn.novalon.gym.manage.datacount.domain.*;
import cn.novalon.gym.manage.datacount.service.IDataStatisticsService;
@@ -46,7 +46,7 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
private DataStatisticsDao dataStatisticsDao;
@Autowired
private RedisUtil redisUtil;
private CacheOperations cacheOperations;
@Autowired
private ObjectMapper objectMapper;
@@ -223,7 +223,7 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
public reactor.core.publisher.Flux<DataStatistics> queryHistoricalStatistics(StatisticsQuery query) {
// 历史统计数据查询(从Redis缓存中获取)
String cacheKey = buildCacheKey(query);
return redisUtil.get(cacheKey, String.class)
return cacheOperations.get(cacheKey, String.class)
.flatMapMany(json -> {
try {
java.util.List<DataStatistics> stats = objectMapper.readValue(json,
@@ -270,9 +270,9 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
String signInJson = objectMapper.writeValueAsString(signInStats);
return reactor.core.publisher.Flux.merge(
redisUtil.setWithExpire(memberKey, memberJson, Duration.ofDays(30).getSeconds()),
redisUtil.setWithExpire(bookingKey, bookingJson, Duration.ofDays(30).getSeconds()),
redisUtil.setWithExpire(signInKey, signInJson, Duration.ofDays(30).getSeconds())
cacheOperations.setWithExpire(memberKey, memberJson, Duration.ofDays(30).getSeconds()),
cacheOperations.setWithExpire(bookingKey, bookingJson, Duration.ofDays(30).getSeconds()),
cacheOperations.setWithExpire(signInKey, signInJson, Duration.ofDays(30).getSeconds())
).then();
} catch (Exception e) {
log.error("Failed to serialize statistics data", e);
@@ -445,13 +445,13 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
public Mono<StatisticsSummary> getStatisticsSummaryWithCache(StatisticsQuery query) {
String cacheKey = buildCacheKey(query);
return redisUtil.get(cacheKey, StatisticsSummary.class)
return cacheOperations.get(cacheKey, StatisticsSummary.class)
.switchIfEmpty(
getStatisticsSummary(query)
.flatMap(summary -> {
try {
String json = objectMapper.writeValueAsString(summary);
return redisUtil.setWithExpire(cacheKey, json, cacheExpireSeconds)
return cacheOperations.setWithExpire(cacheKey, json, cacheExpireSeconds)
.thenReturn(summary);
} catch (Exception e) {
log.error("Failed to serialize statistics summary", e);