# sea-cache **Repository Path**: seaxlab/sea-cache ## Basic Information - **Project Name**: sea-cache - **Description**: 统一缓存抽象,统一语法,切换底层时,上层及业务侧无需修改 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-22 - **Last Updated**: 2026-03-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # sea-cache 统一缓存抽象层:用同一套 `OneCache` API 对接进程内 JVM 缓存、Guava、Caffeine 以及基于 Redis 的远程缓存,便于在开发与测试之间切换实现,或按场景选择后端。 ## 特性 - **接口统一**:`get` / `put` / `invalidate` / `invalidateAll` 语义在各实现间尽量一致(Redis 对 `invalidateAll` 有例外,见下文)。 - **TTL 可组合**:`put(key, value, Duration)` 在 JVM 与 Redis 上支持按条目过期;Guava / Caffeine 包装已构建的 `Cache` 时,通常无法在写入时注入 per-entry TTL(与底层能力一致)。 - **Redis 可测试**:`RedisSyncCommands` 抽象便于在单测中用内存假实现替代真实 Redis。 - **依赖隔离**:Guava、Caffeine、Jedis 均为 `provided`,由业务工程按需引入。 ## 架构 ```mermaid flowchart TB subgraph api["对外 API"] SC["OneCache"] SF["OneCacheFactory"] end subgraph impl["适配实现"] JVM["JvmCache"] G["GuavaCache"] C["CaffeineCache"] R["RedisCache"] end subgraph redis_layer["Redis 扩展点"] RSC["RedisSyncCommands"] CC["CacheCodec"] JEDIS["JedisPoolRedisCommands"] end SF --> SC SC --> JVM SC --> G SC --> C SC --> R R --> RSC R --> CC JEDIS -.-> RSC ``` - **`OneCache`**:核心接口,定义缓存操作与 Javadoc 中的 TTL 语义约定。 - **`OneCacheFactory`**:便捷工厂,创建 JVM / Guava / Caffeine / Redis 等 `OneCache` 实例。 - **进程内实现**:`JvmCache` 基于 `ConcurrentHashMap` + 过期时间;`GuavaCache` / `CaffeineCache` 委托给已配置好的 Guava / Caffeine `Cache`。 - **Redis 实现**:`RedisCache` 将逻辑键编码为 Redis 字符串键,值经 `CacheCodec` 序列化为字符串;底层同步命令由 `RedisSyncCommands` 提供,默认可用 `JedisPoolRedisCommands` 包装 `JedisPool`。 ## 功能流程 ### 读取 `get(key)` 1. 将业务键转为存储层键(Redis:`namespace + codec.toKeySegment(key)`;JVM:直接使用 `key`)。 2. JVM:若条目存在且未过期则返回值,否则惰性清理并返回 `null`。 3. Guava / Caffeine:委托 `getIfPresent`。 4. Redis:`GET` 字符串,非空则 `codec.deserializeValue`。 ### 写入 `put` / `put(key, value, ttl)` 1. **无 TTL 的 `put`**:JVM 使用构造时的默认 TTL(若有),否则视为永不过期;Redis 调用 `SET`(无过期)。 2. **带 `Duration ttl` 的 `put`**: - JVM:计算过期时间戳写入 `ConcurrentHashMap`。 - Redis:`ttl` 为空、零或负时走 `SET`;否则 `SETEX`(秒级,至少 1 秒,亚秒会进位为 1 秒)。 - Guava / Caffeine:多数情况下仅 `put(key, value)`,**忽略**方法参数中的 `ttl`,除非你在构建 `Cache` 时已配置可变过期等策略(以底层库为准)。 ### 失效 `invalidate` / `invalidateAll` - **单键**:JVM `remove`;Guava / Caffeine `invalidate`;Redis `DEL`。 - **全量清空**:JVM 与 Guava / Caffeine 支持 `invalidateAll()`。**Redis 适配器不支持** `invalidateAll()`,会抛出 `UnsupportedOperationException`;全量清理需自行用 `SCAN` + `DEL` 或运维侧能力实现。 ## 使用方法 ### Maven 依赖 在业务模块的 `pom.xml` 中引入(版本号以你仓库中的 `sea-cache` 为准): ```xml io.github.seaxlab sea-cache 1.0.0 ``` 若使用 Guava / Caffeine / Redis,请**额外**添加对应 `provided` 实现依赖(版本需与你环境一致),例如: ```xml com.google.guava guava 29.0-jre com.github.ben-manes.caffeine caffeine 2.9.3 redis.clients jedis 4.3.1 ``` ### JVM 缓存 ```` import com.github.seaxlab.cache.OneCache; import com.github.seaxlab.cache.OneCacheFactory; import java.time.Duration; OneCache cache = OneCacheFactory.jvm(); cache.put("k","v"); String v = cache.get("k"); // 带默认 TTL,单条仍可用 put(k, v, ttl) 覆盖 OneCache withTtl = OneCacheFactory.jvm(Duration.ofMinutes(5)); withTtl. put("session","data"); // 默认 5 分钟 withTtl.put("temp","x",Duration.ofSeconds(10)); // 本条 10 秒 ```` ### Guava ```` import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.github.seaxlab.cache.OneCache; import com.github.seaxlab.cache.OneCacheFactory; Cache guava = CacheBuilder.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build(); OneCache cache = OneCacheFactory.guava(guava); cache.put("k","v"); ```` ### Caffeine ```` import com.github.benmanes.caffeine.cache.Caffeine; import com.github.seaxlab.cache.OneCache; import com.github.seaxlab.cache.OneCacheFactory; com.github.benmanes.caffeine.cache.Cache caffeine = Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build(); OneCache cache = OneCacheFactory.caffeine(caffeine); cache.put("k","v"); ```` ### Redis(Jedis 连接池) 实现或使用自带的 `StringStringCodec` 仅适合 `String`/`String`;其他类型需自行实现 `CacheCodec`(键片段唯一、值可逆序列化为字符串)。 ```` import com.github.seaxlab.cache.OneCache; import com.github.seaxlab.cache.OneCacheFactory; import com.github.seaxlab.cache.redis.StringStringCodec; import redis.clients.jedis.JedisPool; JedisPool pool = new JedisPool("localhost", 6379); OneCache cache = OneCacheFactory.redis(pool, "myapp:cache", StringStringCodec.INSTANCE); cache.put("user:1","payload",Duration.ofHours(1)); // String payload = cache.get("user:1"); // cache.invalidate("user:1"); // cache.invalidateAll(); // 不支持,会抛 UnsupportedOperationException ```` 自定义 Redis 客户端时,实现 `RedisSyncCommands` 并交给工厂: ```` OneCache cache = OneCacheFactory.redis(myRedisSyncCommands, "ns:", StringStringCodec.INSTANCE); ```` ## TTL 与实现差异(速查) | 能力 | JVM | Redis | Guava / Caffeine 包装 | |----------------------------------|---------------------------------|--------------------------|----------------------------------| | 默认 TTL(工厂/构建时) | `OneCacheFactory.jvm(Duration)` | 无内置默认,依赖每次 `put` 的 `ttl` | 由 `CacheBuilder` / `Caffeine` 配置 | | `put(k, v, ttl)` 的 per-entry TTL | 支持 | 支持(`SETEX`,秒级) | 通常忽略参数,仅 `put` | | `invalidateAll` | 支持 | **不支持**(抛异常) | 支持 | ## 构建与测试 ```bash mvn -q test ``` 要求 JDK 8+(与 `pom.xml` 中 `java.version` 一致)。