跳到内容

Cache Starter

受众:开发者 摘要:统一缓存入口。业务代码通过 Cache facade 使用缓存,不直接绑定 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 兼容模式切到 filememory store

不要把强一致业务计数、Redis List / Set / ZSet、分布式锁、Pub/Sub 塞进 Cache(详见 Redis 边界)。

快速开始

yaml
spring:
  open:
    cache:
      default-provider: redis
java
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
配置默认值说明
enabledtrue关闭后 AutoConfiguration 跳过
default-providerredis默认 provider 配置名
key-prefixcache:value所有 key 自动加前缀
default-ttl30m写入未指定 TTL 时使用
cache-null-valuesfalse是否缓存 null(防穿透)
null-value-ttl30snull 值缓存 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。

扩展点与源码骨架

层级主要类型责任
业务 FacadeCache面向业务代码提供短名静态 API,转交给 CacheManager
编排层CacheManager / DefaultCacheManagerkey 前缀、默认 TTL、null 值策略、类型转换、计数更新和 tag 视图
Store SPICacheStore封装单个底层介质的 get / put / forget / ttl
内置 StoreRedisCacheStore / MemoryCacheStore / FileCacheStore分别对接 Redis、本地 Caffeine、本地文件缓存
分组失效TaggedCache通过 tag 版本号参与 key 生成,flush() 时轮转版本让旧 key 失效
内部值包装CacheValue区分“不存在”和“已缓存 null”,支撑防穿透场景
自动配置CacheAutoConfiguration装配内置 store 和默认 manager;Redis store 仅在 RedisManager 可用时注册

分层原则:

  • 业务模块只使用 CacheCacheManager,不要直接依赖 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-providerproviders.<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

相关

Released under the Apache License 2.0.