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

361 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 后端移除 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` 的失败测试**
```java
@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: 实现最小缓存条目与存储类**
```java
public final class InMemoryCacheEntry {
private final Object value;
private final Long expireAtMillis;
}
```
```java
@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: 提交这一小步**
```bash
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` 门面测试**
```java
@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`**
```java
@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: 提交这一小步**
```bash
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: 为限流切换先写失败测试**
```java
@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 脚本依赖**
将核心调用改为:
```java
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: 提交这一小步**
```bash
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: 为监控接口写失败测试**
```java
@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: 提交这一小步**
```bash
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: 提交这一小步**
```bash
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: 提交文档**
```bash
git add doc/2026-04-15-后端移除Redis改造为内存缓存实施计划.md doc/2026-04-15-移除Redis依赖改造为内存缓存后端实施记录.md
git commit -m "补充后端实施记录"
```