缓存构建与配置
2026/1/15大约 4 分钟JavaCaffeine缓存本地缓存后端
缓存构建与配置
Caffeine Builder
Caffeine 使用建造者模式构建缓存,API 与 Guava Cache 高度兼容。
三种缓存类型
1. Cache(手动加载)
Cache<String, User> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
// 手动放入
cache.put("user-1", new User("张三"));
// 获取(可能为 null)
User user = cache.getIfPresent("user-1");
// 获取,不存在时通过 Function 加载
User user2 = cache.get("user-2", key -> userService.getById(key));2. LoadingCache(同步加载)
LoadingCache<String, User> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(key -> userService.getById(key)); // 加载函数
// 获取(自动加载)
User user = cache.get("user-1");
// 批量获取
Map<String, User> users = cache.getAll(Arrays.asList("1", "2", "3"));3. AsyncLoadingCache(异步加载)
AsyncLoadingCache<String, User> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.buildAsync(key -> userService.getById(key));
// 异步获取
CompletableFuture<User> future = cache.get("user-1");
future.thenAccept(user -> System.out.println(user));
// 同步获取
User user = cache.get("user-1").join();
// 批量异步获取
CompletableFuture<Map<String, User>> futureMap = cache.getAll(Arrays.asList("1", "2"));4. AsyncCache(手动异步)
AsyncCache<String, User> cache = Caffeine.newBuilder()
.maximumSize(1000)
.buildAsync();
// 异步获取,不存在时加载
CompletableFuture<User> future = cache.get("user-1",
key -> CompletableFuture.supplyAsync(() -> userService.getById(key)));容量配置
maximumSize - 最大条目数
Cache<String, Object> cache = Caffeine.newBuilder()
.maximumSize(10000) // 最多 10000 个条目
.build();maximumWeight - 最大权重
Cache<String, List<String>> cache = Caffeine.newBuilder()
.maximumWeight(100000) // 最大权重
.weigher((String key, List<String> value) -> value.size()) // 权重计算
.build();initialCapacity - 初始容量
Cache<String, Object> cache = Caffeine.newBuilder()
.initialCapacity(100) // 初始容量
.maximumSize(10000)
.build();过期配置
expireAfterWrite - 写入后过期
Cache<String, Object> cache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
// 或使用 Duration
Cache<String, Object> cache2 = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(10))
.build();expireAfterAccess - 访问后过期
Cache<String, Object> cache = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build();expireAfter - 自定义过期策略
Cache<String, User> cache = Caffeine.newBuilder()
.expireAfter(new Expiry<String, User>() {
@Override
public long expireAfterCreate(String key, User user, long currentTime) {
// 创建后的过期时间(纳秒)
return user.isVip() ?
TimeUnit.HOURS.toNanos(1) : // VIP 用户缓存 1 小时
TimeUnit.MINUTES.toNanos(10); // 普通用户缓存 10 分钟
}
@Override
public long expireAfterUpdate(String key, User user, long currentTime, long currentDuration) {
// 更新后的过期时间
return currentDuration; // 保持不变
}
@Override
public long expireAfterRead(String key, User user, long currentTime, long currentDuration) {
// 读取后的过期时间
return currentDuration; // 保持不变
}
})
.build(key -> userService.getById(key));refreshAfterWrite - 写入后刷新
LoadingCache<String, User> cache = Caffeine.newBuilder()
.maximumSize(10000)
.refreshAfterWrite(1, TimeUnit.MINUTES) // 写入 1 分钟后刷新
.build(key -> userService.getById(key));刷新机制
refreshAfterWrite 是惰性刷新,只有在下次访问时才会触发。刷新期间会返回旧值,不会阻塞。
引用配置
weakKeys - 弱引用键
Cache<Object, Object> cache = Caffeine.newBuilder()
.weakKeys()
.build();weakValues - 弱引用值
Cache<String, Object> cache = Caffeine.newBuilder()
.weakValues()
.build();softValues - 软引用值
Cache<String, Object> cache = Caffeine.newBuilder()
.softValues()
.build();注意
使用弱引用或软引用时,不能同时使用 maximumSize 或 maximumWeight。
监听配置
removalListener - 移除监听
Cache<String, User> cache = Caffeine.newBuilder()
.maximumSize(10000)
.removalListener((String key, User user, RemovalCause cause) -> {
log.info("缓存移除: key={}, cause={}", key, cause);
})
.build();evictionListener - 淘汰监听
只监听因容量或过期被淘汰的条目,不包括手动删除。
Cache<String, User> cache = Caffeine.newBuilder()
.maximumSize(10000)
.evictionListener((String key, User user, RemovalCause cause) -> {
log.info("缓存淘汰: key={}, cause={}", key, cause);
})
.build();writer - 写入监听
Cache<String, User> cache = Caffeine.newBuilder()
.maximumSize(10000)
.writer(new CacheWriter<String, User>() {
@Override
public void write(String key, User user) {
// 写入时回调
log.info("缓存写入: key={}", key);
}
@Override
public void delete(String key, User user, RemovalCause cause) {
// 删除时回调
log.info("缓存删除: key={}, cause={}", key, cause);
}
})
.build();统计配置
Cache<String, Object> cache = Caffeine.newBuilder()
.maximumSize(10000)
.recordStats() // 开启统计
.build();
// 获取统计信息
CacheStats stats = cache.stats();
System.out.println("命中率: " + stats.hitRate());
System.out.println("加载次数: " + stats.loadCount());调度器配置
Cache<String, Object> cache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.scheduler(Scheduler.systemScheduler()) // 使用系统调度器
.build();调度器用于定时清理过期条目,默认是惰性清理。
完整配置示例
LoadingCache<String, User> cache = Caffeine.newBuilder()
// 容量配置
.initialCapacity(100)
.maximumSize(10000)
// 过期配置
.expireAfterWrite(30, TimeUnit.MINUTES)
.refreshAfterWrite(5, TimeUnit.MINUTES)
// 统计配置
.recordStats()
// 监听配置
.removalListener((key, value, cause) -> {
log.info("缓存移除: key={}, cause={}", key, cause);
})
// 调度器
.scheduler(Scheduler.systemScheduler())
// 构建
.build(key -> userService.getById(key));小结
Caffeine 提供了丰富的配置选项,包括容量限制、过期策略、引用类型、监听器等。API 与 Guava Cache 高度兼容,同时提供了更强大的异步支持和自定义过期策略。
面试题预览
常见面试题
- Caffeine 的三种缓存类型有什么区别?
- expireAfter 自定义过期策略如何实现?
- refreshAfterWrite 的刷新机制是怎样的?
