# memo-agent **Repository Path**: ingrun/memo-agent ## Basic Information - **Project Name**: memo-agent - **Description**: 轻量 Java 方法级缓存组件。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-13 - **Last Updated**: 2026-07-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MemoAgent 轻量 Java 方法级缓存组件。支持**内存缓存**和 **Redis 缓存**两种后端,提供统一的静态门面 API。 --- ## 快速开始 ### 添加依赖 ```xml cn.ingrun memo-agent-core 1.0.0 cn.ingrun memo-agent-sb-redis 1.0.0 ``` ### Redis 缓存模式(Spring Boot) 引入 `memo-agent-sb-redis` 后自动装配,无需手动创建 Handler: ```yml # application.yml spring: redis: host: localhost port: 6379 ``` ```java // 直接使用 MemoAgent 静态方法 @RestController public class UserController { @GetMapping("/user/{id}") public UserInfo getUser(@PathVariable String id) { return MemoAgent.computeIfAbsent("user:" + id, () -> queryDB(id)); } } ``` 自动装配的 Bean: - `StringRedisTemplate`(Spring Boot 默认提供) - `JacksonRedisSerializer` — 默认序列化器 - `RedisMemoCache` — 基于 Redis 的 MemoCache - `MemoConfigManage` + `MemoHandler` — 自动初始化 MemoAgent ### 示例:缓存一个慢查询 ```java // 配置命名空间(可选) MemoAgent.config("user").setTtl(30_000).setNullValueCache(true); // 生成 key 并缓存 String key = Util.genKey("user", new QueryParam(1)); UserInfo r1 = MemoAgent.computeIfAbsent(key, 10_000, () -> getUserFromDB(param)); UserInfo r2 = MemoAgent.computeIfAbsent(key, 10_000, () -> getUserFromDB(param)); // r2 命中缓存,不会执行 getUserFromDB ``` --- ## API 参考 ### MemoAgent — 唯一入口 | 方法 | 说明 | |------|------| | ` R computeIfAbsent(String key, long ttl, Supplier)` | 缓存读取,未命中执行 supplier 并缓存 | | ` R computeIfAbsent(String key, Supplier)` | 同上,TTL 由配置决定 | | ` R get(String key)` | 只读查询,不触发回源 | | `put(String key, Object value, long ttl)` | 覆盖缓存 | | `remove(String key)` | 移除缓存 | | `updateTtl(String key, long ttl)` | 修改 TTL | | `config(String cacheName)` | 获取命名空间配置(链式设置) | ### Util — Key 生成 | 方法 | 说明 | |------|------| | `genKey(String prefix, Object... args)` | `prefix:json(arg1):json(arg2)...` | 参数通过 Jackson 序列化为 JSON,确保"值相等则 key 相等"。 ### MemoConfig — 配置 ```java MemoAgent.config("user") .setTtl(30_000) // TTL (ms),0=继承全局,-1=永不过期 .setNullValueCache(true) // 是否缓存 null 值 .setRedisSerializer(serializer); // Redis 序列化器 ``` 哨兵值语义: | 字段 | 哨兵值 | 含义 | |------|--------|------| | `ttl` | `0` | 合并时继承全局 TTL | | `nullValueCache` | `null` | 合并时继承全局策略 | | `redisSerializer` | `null` | 合并时继承全局序列化器 | ### MemoConfigManage — 三层配置 **默认值 → 全局 → 按命名空间(前缀匹配)** ```java MemoConfigManage mgr = new MemoConfigManage(); mgr.getGlobalConfig().setTtl(60_000); // 全局 TTL 60s mgr.getConfig("user").setTtl(30_000); // user 命名空间 TTL=30s mgr.getConfig("user:detail").setNullValueCache(true); // getMemoConfig 按最长前缀匹配 MemoConfig c = mgr.getMemoConfig("user:detail:123"); // → ttl=30000, nullValueCache=true ``` --- ## SPI 接口 ### MemoCache — 缓存后端 ```java public interface MemoCache { void setCache(String key, Object value, long ttl); Object getCache(String key); void removeCache(String key); void updateTtl(String key, long ttl); long getRemainingTtl(String key); boolean containsKey(String key); // 区分"缓存了 null"和"key 不存在" } ``` 内置实现: | 实现 | 模块 | 存储 | 分布式 | |------|------|------|:---:| | `MemoryMemoCache` | core | ConcurrentHashMap + 惰性删除 | 不支持 | | `RedisMemoCache` | sb-redis | Redis + 原生 EXPIRE | 支持 | ### RedisSerializer — 序列化器 ```java public interface RedisSerializer { byte[] serialize(T t); T deserialize(byte[] bytes); } ``` 内置实现: - `JacksonRedisSerializer` — 基于 Jackson,包装模式存 `className + JSON` - 演示参见 `memo-agent-demo`,含 `FastJsonRedisSerializer` 示例 ### 自定义序列化器 ```java // 实现接口 public class MySerializer implements RedisSerializer { public byte[] serialize(Object obj) { ... } public Object deserialize(byte[] bytes) { ... } } // 注册为 Bean 覆盖默认的 JacksonRedisSerializer @Bean public RedisSerializer redisSerializer() { return new MySerializer(); } ``` --- ## 技术栈 - **Java 8** - **Spring Boot 2.7.5**(仅 sb-redis / demo 模块) - **Spring Data Redis** — Redis 缓存后端 - **Jackson** — 默认 JSON 序列化 - **SLF4J** — 日志门面 - **Lombok** — 编译期,provided scope - **JUnit 4** — 66 个单元测试