Caffeine
Caffeine 是基于 Java 8 的高性能进程内缓存库,是 Spring Boot 2.x+ 默认的本地缓存实现。相比 Guava Cache,引入了 W-TinyLFU 淘汰算法,命中率显著更高。
适合:单机高频读场景(热点数据、配置缓存);不适合:多节点共享数据(用 Redis)。
快速上手
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.8</version>
</dependency>手动缓存(Cache)
Cache<String, User> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats()
.build();
cache.put("user:1", user);
User u = cache.getIfPresent("user:1"); // 不存在返回 null
User u = cache.get("user:1", k -> userRepo.findById(1L)); // 不存在则加载
cache.invalidate("user:1");
cache.invalidateAll();自动加载缓存(LoadingCache)
LoadingCache<String, User> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(key -> userRepo.findByKey(key)); // 缺失时自动调用
User user = cache.get("user:1");
Map<String, User> users = cache.getAll(List.of("user:1", "user:2"));异步加载缓存(AsyncLoadingCache)
AsyncLoadingCache<String, User> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.buildAsync(key -> userRepo.findByKeyAsync(key)); // 返回 CompletableFuture
CompletableFuture<User> future = cache.get("user:1");过期策略
| 策略 | 方法 | 说明 |
|---|---|---|
| 写后过期 | expireAfterWrite(duration) | 写入后固定时间过期 |
| 访问后过期 | expireAfterAccess(duration) | 最后一次读/写后固定时间过期 |
| 自定义过期 | expireAfter(Expiry) | 按 key/value 动态计算过期时间 |
| 固定大小 | maximumSize(n) | 超出时按 W-TinyLFU 淘汰 |
| 权重上限 | maximumWeight(w) | 按条目权重总和限制 |
统计监控
CacheStats stats = cache.stats();
stats.hitRate(); // 命中率
stats.loadCount(); // 加载次数
stats.evictionCount(); // 驱逐次数
stats.averageLoadPenalty(); // 平均加载耗时(ns)Spring Boot 集成
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=500,expireAfterWrite=600s@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats());
return manager;
}
}@Cacheable(value = "users", key = "#id")
public User getUser(Long id) { ... }
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) { ... }
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) { ... }W-TinyLFU 算法
全部缓存空间
├── Window 区(1%):新进入数据先放这里,防止冷数据污染
└── Main 区(99%)
├── Protected 区(80%):高频访问数据
└── Probation 区(20%):候选区,频率低的在此被淘汰
新数据进 Window → 晋升 Probation → 高频则升入 Protected,否则被淘汰。对突发流量和循环扫描的抵抗性优于纯 LRU。
Caffeine vs Guava Cache
| 维度 | Caffeine | Guava Cache |
|---|---|---|
| 淘汰算法 | W-TinyLFU | LRU 近似 |
| 命中率 | 更高 | 较低 |
| 异步加载 | 支持 | 不支持 |
| Spring Boot 默认 | 是(2.x+) | 否 |