Files
loan-pricing/doc/2026-04-15-后端移除Redis改造为内存缓存实施计划.md

12 KiB
Raw Blame History

后端移除 Redis 改造为内存缓存实施计划

For agentic workers: REQUIRED: Use superpowers:executing-plans to implement this plan in this repository. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 移除后端 Redis 依赖,并在单实例 JVM 内存中承接登录态、验证码、限流、防重提交、参数/字典缓存、在线用户和缓存监控能力。

Architecture: 保留现有 RedisCache 业务入口,底层替换为基于 ConcurrentHashMap 的本地缓存存储,减少对现有业务代码的侵入。限流、在线用户、缓存监控等能力继续沿用现有 key 规则,仅替换存储实现与统计来源。

Tech Stack: Java 8, Spring Boot 2.x, Spring Security, Maven, JUnit 5


文件结构

Create:

  • ruoyi-common/src/main/java/com/ruoyi/common/core/cache/InMemoryCacheEntry.java
  • ruoyi-common/src/main/java/com/ruoyi/common/core/cache/InMemoryCacheStats.java
  • ruoyi-common/src/main/java/com/ruoyi/common/core/cache/InMemoryCacheStore.java
  • ruoyi-common/src/test/java/com/ruoyi/common/core/cache/InMemoryCacheStoreTest.java
  • ruoyi-common/src/test/java/com/ruoyi/common/core/redis/RedisCacheTest.java
  • ruoyi-framework/src/test/java/com/ruoyi/framework/aspectj/RateLimiterAspectTest.java
  • ruoyi-framework/src/test/java/com/ruoyi/framework/web/service/TokenServiceLocalCacheTest.java
  • ruoyi-admin/src/test/java/com/ruoyi/web/controller/monitor/CacheControllerTest.java

Modify:

  • pom.xml
  • ruoyi-common/pom.xml
  • ruoyi-framework/pom.xml
  • ruoyi-admin/pom.xml
  • ruoyi-admin/src/main/resources/application.yml
  • ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
  • ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
  • ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java

Delete:

  • ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
  • ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java

Verify existing behavior against:

  • ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
  • ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
  • ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
  • ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java
  • ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
  • ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
  • ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
  • ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
  • ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java

Task 1: 搭建内存缓存底座

Files:

  • Create: ruoyi-common/src/main/java/com/ruoyi/common/core/cache/InMemoryCacheEntry.java

  • Create: ruoyi-common/src/main/java/com/ruoyi/common/core/cache/InMemoryCacheStats.java

  • Create: ruoyi-common/src/main/java/com/ruoyi/common/core/cache/InMemoryCacheStore.java

  • Test: ruoyi-common/src/test/java/com/ruoyi/common/core/cache/InMemoryCacheStoreTest.java

  • Step 1: 先写 InMemoryCacheStore 的失败测试

@Test
void shouldExpireEntryAfterTimeout() throws Exception {
    InMemoryCacheStore store = new InMemoryCacheStore();
    store.set("captcha:1", "1234", 50L, TimeUnit.MILLISECONDS);
    Thread.sleep(80L);
    assertNull(store.get("captcha:1"));
}
  • Step 2: 运行测试确认失败

Run: mvn -pl ruoyi-common -Dtest=InMemoryCacheStoreTest test Expected: FAIL提示 InMemoryCacheStore 或相关方法不存在

  • Step 3: 实现最小缓存条目与存储类
public final class InMemoryCacheEntry {
    private final Object value;
    private final Long expireAtMillis;
}
@Component
public class InMemoryCacheStore {
    private final ConcurrentHashMap<String, InMemoryCacheEntry> entries = new ConcurrentHashMap<>();
}
  • Step 4: 为底座补齐核心能力

实现并覆盖测试:

  • set/get

  • set(key, value, timeout, unit)

  • hasKey

  • delete

  • delete(Collection<String>)

  • keys(pattern)

  • expire/getExpire

  • increment

  • clear

  • snapshot

  • Step 5: 运行测试确认通过

Run: mvn -pl ruoyi-common -Dtest=InMemoryCacheStoreTest test Expected: PASS

  • Step 6: 提交这一小步
git add ruoyi-common/src/main/java/com/ruoyi/common/core/cache ruoyi-common/src/test/java/com/ruoyi/common/core/cache/InMemoryCacheStoreTest.java
git commit -m "新增内存缓存底座"

Task 2: 将 RedisCache 改为内存缓存门面

Files:

  • Modify: ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java

  • Test: ruoyi-common/src/test/java/com/ruoyi/common/core/redis/RedisCacheTest.java

  • Step 1: 先写 RedisCache 门面测试

@Test
void shouldReadAndDeleteCachedObject() {
    RedisCache cache = new RedisCache(new InMemoryCacheStore());
    cache.setCacheObject("login_tokens:abc", "value");
    assertEquals("value", cache.getCacheObject("login_tokens:abc"));
    assertTrue(cache.deleteObject("login_tokens:abc"));
}
  • Step 2: 运行测试确认失败

Run: mvn -pl ruoyi-common -Dtest=RedisCacheTest test Expected: FAIL提示当前 RedisCache 仍依赖 RedisTemplate

  • Step 3: 将 RedisCache 改成构造注入 InMemoryCacheStore
@Component
public class RedisCache {
    private final InMemoryCacheStore cacheStore;
    public RedisCache(InMemoryCacheStore cacheStore) {
        this.cacheStore = cacheStore;
    }
}
  • Step 4: 保留原有业务方法并补充监控/限流能力

补齐:

  • setCacheObject/getCacheObject

  • setCacheMap/getCacheMap

  • setCacheList/getCacheList

  • setCacheSet/getCacheSet

  • deleteObject

  • keys

  • increment

  • getCacheStats

  • clear

  • Step 5: 运行测试确认通过

Run: mvn -pl ruoyi-common -Dtest=RedisCacheTest,InMemoryCacheStoreTest test Expected: PASS

  • Step 6: 提交这一小步
git add ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java ruoyi-common/src/test/java/com/ruoyi/common/core/redis/RedisCacheTest.java
git commit -m "改造缓存门面为内存实现"

Task 3: 用内存计数替换限流实现

Files:

  • Modify: ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java

  • Test: ruoyi-framework/src/test/java/com/ruoyi/framework/aspectj/RateLimiterAspectTest.java

  • Step 1: 为限流切换先写失败测试

@Test
void shouldRejectRequestWhenCountExceeded() throws Throwable {
    RedisCache cache = new RedisCache(new InMemoryCacheStore());
    RateLimiterAspect aspect = new RateLimiterAspect(cache);
    // 连续触发三次阈值为2第三次应抛 ServiceException
}
  • Step 2: 运行测试确认失败

Run: mvn -pl ruoyi-framework -am -Dtest=RateLimiterAspectTest test Expected: FAIL提示当前 RateLimiterAspect 仍依赖 RedisTemplate/RedisScript

  • Step 3: 删除 RedisTemplate 和 Lua 脚本依赖

将核心调用改为:

long number = redisCache.increment(combineKey, time, TimeUnit.SECONDS);
if (number > count) {
    throw new ServiceException("访问过于频繁,请稍候再试");
}
  • Step 4: 运行测试确认通过

Run: mvn -pl ruoyi-framework -am -Dtest=RateLimiterAspectTest test Expected: PASS

  • Step 5: 提交这一小步
git add ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java ruoyi-framework/src/test/java/com/ruoyi/framework/aspectj/RateLimiterAspectTest.java
git commit -m "改造限流为内存计数"

Task 4: 调整缓存监控接口到内存统计

Files:

  • Modify: ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java

  • Test: ruoyi-admin/src/test/java/com/ruoyi/web/controller/monitor/CacheControllerTest.java

  • Step 1: 为监控接口写失败测试

@Test
void shouldReturnInMemoryCacheStats() {
    // 断言返回 info.cache_type == "IN_MEMORY"
    // 断言返回 info.cache_mode == "single-instance"
}
  • Step 2: 运行测试确认失败

Run: mvn -pl ruoyi-admin -am -Dtest=CacheControllerTest test Expected: FAIL提示当前接口仍返回 Redis 信息结构

  • Step 3: 将 CacheController 改为依赖 RedisCache

实现行为:

  • getInfo() 返回内存缓存统计

  • getKeys() 通过 redisCache.keys(pattern) 获取

  • getCacheValue() 将对象序列化为字符串

  • clearCacheName()clearCacheKey()clearCacheAll() 走内存门面

  • Step 4: 运行测试确认通过

Run: mvn -pl ruoyi-admin -am -Dtest=CacheControllerTest test Expected: PASS

  • Step 5: 手工冒烟现有依赖方

检查以下类不需要额外逻辑改造:

  • TokenService
  • SysLoginService
  • SysRegisterService
  • SysPasswordService
  • SameUrlDataInterceptor
  • SysUserOnlineController
  • SysConfigServiceImpl
  • DictUtils

Expected: 仅继续依赖 RedisCache 即可,无需改 key 规则

  • Step 6: 提交这一小步
git add ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java ruoyi-admin/src/test/java/com/ruoyi/web/controller/monitor/CacheControllerTest.java
git commit -m "改造缓存监控为内存统计"

Task 5: 删除 Redis 配置与依赖

Files:

  • Modify: pom.xml

  • Modify: ruoyi-common/pom.xml

  • Modify: ruoyi-framework/pom.xml

  • Modify: ruoyi-admin/pom.xml

  • Modify: ruoyi-admin/src/main/resources/application.yml

  • Delete: ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java

  • Delete: ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java

  • Step 1: 删除 Maven 中 Redis 相关依赖

删除:

  • spring-boot-starter-data-redis

  • commons-pool2

  • Step 2: 删除应用配置中的 spring.redis 配置块

保留其它配置项不变,只移除 Redis 相关字段

  • Step 3: 删除 Redis 基础设施类

删除:

  • RedisConfig

  • FastJson2JsonRedisSerializer

  • Step 4: 全量编译验证

Run: mvn clean package -DskipTests Expected: BUILD SUCCESS

  • Step 5: 运行后端相关测试

Run: mvn -pl ruoyi-common,ruoyi-framework,ruoyi-admin -am test Expected: BUILD SUCCESS

  • Step 6: 启动后端做接口冒烟

Run: mvn -pl ruoyi-admin -am spring-boot:run Expected:

  • 应用可正常启动

  • 不再尝试连接 Redis

  • 登录、验证码、缓存监控接口正常可用

  • Step 7: 停止测试进程

结束 spring-boot:run 启动的 Java 进程,避免遗留后台服务

  • Step 8: 提交这一小步
git add pom.xml ruoyi-common/pom.xml ruoyi-framework/pom.xml ruoyi-admin/pom.xml ruoyi-admin/src/main/resources/application.yml ruoyi-framework/src/main/java/com/ruoyi/framework/config
git commit -m "移除Redis依赖与配置"

Task 6: 补充实施记录

Files:

  • Modify: doc/2026-04-15-后端移除Redis改造为内存缓存实施计划.md

  • Create or Modify: doc/2026-04-15-移除Redis依赖改造为内存缓存后端实施记录.md

  • Step 1: 记录最终实际修改文件和偏差

记录内容至少包括:

  • 实际变更文件

  • 测试命令

  • 冒烟结论

  • 与计划有无偏差

  • Step 2: 提交文档

git add doc/2026-04-15-后端移除Redis改造为内存缓存实施计划.md doc/2026-04-15-移除Redis依赖改造为内存缓存后端实施记录.md
git commit -m "补充后端实施记录"