📦 1. ExpiringMap 是什么?
net.jodah:expiringmap 是一个 轻量级、高性能的 Java Map 实现,内置 key 过期机制。它非常适合作为 临时缓存、验证码存储、限流、token 存储 等用途。
特点:
-
每个 key 可以设置独立过期时间
-
支持两种过期策略:
- CREATED:从创建开始计时
- ACCESSED:每次访问都会重置 TTL
-
自动清理过期 key
-
支持过期回调(EntryExpiredListener)
-
性能优于 ConcurrentHashMap + ScheduledExecutorService 的自制方案
📥 2. 引入依赖
Maven:
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.10</version>
</dependency>
Gradle:
implementation 'net.jodah:expiringmap:0.5.10'
🧰 3. 基本使用
⭐ 创建一个 ExpiringMap
ExpiringMap<String, String> map = ExpiringMap.builder()
.expiration(10, TimeUnit.SECONDS) // 默认过期时间
.variableExpiration() // 允许每个 key 单独设置 TTL
.build();
⭐ 放入带过期时间的 Key
map.put("token", "abc123", 5, TimeUnit.SECONDS);
⭐ 获取
String v = map.get("token"); // 5秒后会返回 null
⭐ 检查是否过期
过期 key 会被自动删除,但你也可以自己检查:
map.containsKey("token"); // false when expired
⏰ 4. 过期策略(ExpirationPolicy)
两种策略:
✔ CREATED(默认)
Key 写入后开始计时,每次访问不会延长 TTL
map.put("a", "1", ExpirationPolicy.CREATED, 5, TimeUnit.SECONDS);
✔ ACCESSED(滑动过期)
每次访问都会刷新 TTL → 类似会话(session)
map.put("user-session", "u1", ExpirationPolicy.ACCESSED, 30, TimeUnit.MINUTES);
🔔 5. 监听 Key 过期事件
监听器可以用于:
- 清理资源
- 打印日志
- 执行回调
示例:
ExpiringMap<String, String> map = ExpiringMap.builder()
.expiration(10, TimeUnit.SECONDS)
.expirationListener((key, value) -> {
System.out.println("Key expired: " + key + " => " + value);
})
.build();
🚀 6. 常见使用场景(真实“厂家”使用方法)
以下是企业工程中最常用的几种模式👇
🧩 6.1 验证码(SMS / 邮箱验证码)存储
map.put(phone, code, 2, TimeUnit.MINUTES);
使用方(厂家):
用于短信平台、Web 登录验证码校验等。
🧩 6.2 登录 Token / 临时 Token 存储
map.put("token-123", userId, ExpirationPolicy.CREATED, 30, TimeUnit.MINUTES);
厂家用途:
- OAuth2 implicit token
- 邮箱“临时访问链接”
- 重置密码 token
🧩 6.3 防重处理(幂等去重)
map.put(requestId, true, 10, TimeUnit.SECONDS);
厂家用途:
支付回调、消息重复消费、HTTP 防重复提交。
🧩 6.4 限流(Rate Limiter)计数器
Integer count = map.getOrDefault(ip, 0);
map.put(ip, count + 1, ExpirationPolicy.CREATED, 1, TimeUnit.MINUTES);
厂家用途:
接口防刷、IP 限制、短信限流。
🧩 6.5 缓存热点数据(轻量缓存)
map.put("product:123", productJson, 30, TimeUnit.SECONDS);
厂家用途:
无需完整 Redis,可以作为服务内部本地缓存。
🧱 7. 和其他方案对比
| 方案 | 特点 | 性能 | 适用场景 |
|---|---|---|---|
| ExpiringMap | 内存缓存,精确 TTL | 高 | 单机缓存、轻量级、临时数据 |
| ConcurrentHashMap+ScheduledExecutor | 手写实现 | 中 | 可定制但复杂 |
| Caffeine | 更强缓存(LRU+TTL) | 最高 | 高并发、高性能缓存 |
| Redis | 分布式缓存 | 网络延迟 | 多节点共享缓存、跨服务 |
ExpiringMap 适合 轻量、单机、临时 的使用场景。
📚 8. 最佳实践
- 不要放入大量数据(内存缓存)
- 对高并发缓存建议用 Caffeine
- 分布式系统不要把它当 Redis 用
- 可配合 Spring 使用(作为服务内部缓存)
使用:
- ⭐ 一个完整的使用案例(比如验证码服务)
- ⭐ 封装一个 ExpiringMap 工具类
- ⭐ 实现一个 TokenManager(登录 token)
- ⭐ 教你用 ExpiringMap 做限流
- ⭐ 教你用 ExpiringMap + Spring Boot 集成