Cache Starter
受众:开发者 摘要:统一缓存入口。业务代码通过
Cachefacade 使用缓存,不直接绑定 Redis / 内存 / 文件实现。本文档作为 starter 文档的标准模板,其他 starter 文档遵循同样的章节结构(详见
.ai/STYLE.md)。
何时使用
| 场景 | 建议 |
|---|---|
| 用户信息、配置、字典等读多写少的数据 | Cache.remember(key, ttl, loader) |
| 接口结果防抖、防穿透 | Cache.put(key, value, ttl) |
| 初始化标记、轻量去重 | Cache.add(key, value, ttl) |
| 简单计数器 | Cache.increment(key) / decrement(key) |
| 多实例共享 | 切到 redis store |
| 单进程诊断 / lite 兼容模式 | 切到 file 或 memory store |
不要把强一致业务计数、Redis List / Set / ZSet、分布式锁、Pub/Sub 塞进 Cache(详见 Redis 边界)。
快速开始
yaml
spring:
open:
cache:
default-provider: redisjava
import com.springopen.starter.cache.Cache;
import java.time.Duration;
User user = Cache.remember("user:1", Duration.ofMinutes(10), () -> userService.findById(1L));
Cache.forget("user:1");Facade API
| 方法 | 说明 |
|---|---|
Cache.get(key) | 读取缓存 |
Cache.getOrDefault(key, defaultValue) | 读取缓存,不存在返回默认值 |
Cache.get(key, type) | 按类型读取 |
Cache.has(key) | 判断是否存在 |
Cache.add(key, value) / add(key, value, ttl) | 仅当 key 不存在时写入 |
Cache.put(key, value) / put(key, value, ttl) | 写入(覆盖) |
Cache.putMany(values) / putMany(values, ttl) | 批量写入 |
Cache.forever(key, value) | 写入不过期 |
Cache.remember(key, loader) / remember(key, ttl, loader) | 不存在时执行 loader 并写入 |
Cache.rememberForever(key, loader) | 不存在时执行 loader 并写入不过期 |
Cache.pull(key) | 读取后删除 |
Cache.many(keys) | 批量读取 |
Cache.increment(key) / increment(key, delta) | 自增计数 |
Cache.decrement(key) / decrement(key, delta) | 自减计数 |
Cache.ttl(key) | 剩余过期时间(永久或不存在返回 null) |
Cache.forget(key) | 删除 |
Cache.forgetMany(keys) | 批量删除,返回实际删除数量 |
标签分组失效
java
Cache.tags("users", "profiles")
.put("1", user, Duration.ofMinutes(30));
User user = Cache.tags("users", "profiles")
.remember("1", Duration.ofMinutes(30), () -> userService.findById(1L));
Cache.tags("users").flush();flush() 不扫描底层缓存,而是轮换 tag 版本号让旧 key 自动失效。Redis / memory / file store 都能使用同一套机制。
配置项
yaml
spring:
open:
cache:
enabled: true # 启用开关
default-provider: redis # 默认 provider
key-prefix: cache:value # key 前缀
default-ttl: 30m # 默认 TTL
cache-null-values: false # 缓存 null 值(防穿透)
null-value-ttl: 30s # null 值 TTL
providers:
memory:
provider: memory
maximum-size: 10000
file:
provider: file
enabled: true
root: ${APP_STORAGE_DIR:${user.dir}/storage}/runtime/cache
redis:
provider: redis| 配置 | 默认值 | 说明 |
|---|---|---|
enabled | true | 关闭后 AutoConfiguration 跳过 |
default-provider | redis | 默认 provider 配置名 |
key-prefix | cache:value | 所有 key 自动加前缀 |
default-ttl | 30m | 写入未指定 TTL 时使用 |
cache-null-values | false | 是否缓存 null(防穿透) |
null-value-ttl | 30s | null 值缓存 TTL |
providers.<name>.provider | - | 真实 Provider |
providers.<name>.<provider-config> | - | Provider 特定配置 |
开发期不保留旧配置兼容;Cache 统一使用 default-provider / providers.*。
Provider / Store
| Store | 说明 | 适用场景 |
|---|---|---|
redis | 基于 Redis | 默认推荐,多实例共享缓存 |
memory | 本机内存(Caffeine) | 单测、隔离诊断、兼容模式 |
file | 本地文件 | 无 Redis 的单进程诊断 / 兼容模式 |
storage/runtime/cache 是临时缓存目录,可以删除;实际缓存文件由 storage/.gitignore 忽略,不进 Git。需要长期保存的数据不要放入 Cache。
扩展点与源码骨架
| 层级 | 主要类型 | 责任 |
|---|---|---|
| 业务 Facade | Cache | 面向业务代码提供短名静态 API,转交给 CacheManager |
| 编排层 | CacheManager / DefaultCacheManager | key 前缀、默认 TTL、null 值策略、类型转换、计数更新和 tag 视图 |
| Store SPI | CacheStore | 封装单个底层介质的 get / put / forget / ttl |
| 内置 Store | RedisCacheStore / MemoryCacheStore / FileCacheStore | 分别对接 Redis、本地 Caffeine、本地文件缓存 |
| 分组失效 | TaggedCache | 通过 tag 版本号参与 key 生成,flush() 时轮转版本让旧 key 失效 |
| 内部值包装 | CacheValue | 区分“不存在”和“已缓存 null”,支撑防穿透场景 |
| 自动配置 | CacheAutoConfiguration | 装配内置 store 和默认 manager;Redis store 仅在 RedisManager 可用时注册 |
分层原则:
- 业务模块只使用
Cache或CacheManager,不要直接依赖 Redis / Caffeine / 文件缓存实现。 - Store 只表达底层介质能力;默认 TTL、null 值缓存、key 前缀和 tag 失效由 Manager 统一处理。
TaggedCache.flush()不扫描底层缓存,也不删除旧 key;它通过轮转 tag 版本让旧 key 失效,旧数据等待 TTL 或外部清理。- Redis List / Set / ZSet、分布式锁、Pub/Sub 等专用能力不进入 Cache,继续使用 Data Redis / Redisson 底座。
- 新增 store 时实现
CacheStore并注册为 Spring Bean;业务侧配置default-provider或providers.<name>.provider选择即可。
扩展自定义 Store
实现 CacheStore SPI 并注册为 Spring Bean:
java
@Component
public class MyStore implements CacheStore {
@Override
public String name() { return "my-store"; }
// ...
}然后在配置引用:
yaml
spring:
open:
cache:
providers:
my:
provider: my-store与 Redis 的边界
常规业务缓存统一用 Cache facade。以下场景使用 Redis / Redisson 专用能力(不塞进 Cache,避免把 Cache 做成 Redis 复刻版):
- Redis List / Set / ZSet 等数据结构
- Pub/Sub、Topic、多实例广播
- 分布式锁、看门狗、复杂协调
- Queue、Scheduler、WebSocket 等框架内部运行时
注意事项
- 默认不缓存
null,需要防穿透时再开启cache-null-values,并设置较短 TTL - 缓存 key 业务可读:
user:profile:1而非u_p_1 - 多实例部署优先
redis - 文件缓存只用于单进程诊断或兼容模式,不适合普通开发联调、生产共享或多实例部署
increment/decrement适合缓存计数;强一致业务计数应落数据库或专门计数模型
验证命令
bash
./mvnw -pl spring-open-starters/spring-open-starter-cache -am test -DskipITs
./mvnw -pl spring-open-application -am test -DskipITs -DskipFrontend相关
- 全局配置模型:configuration.md / config.md
- Redis 底座:redis.md
- Storage(持久化文件):storage.md
- Provider 扩展模型:provider.md