缓存构建与配置
2026/1/15大约 4 分钟JavaGuava缓存本地缓存后端
缓存构建与配置
CacheBuilder 详解
CacheBuilder 是 Guava Cache 的核心构建器,采用建造者模式,支持链式调用配置各种缓存参数。
两种缓存类型
1. Cache(手动加载)
需要手动调用 put 方法放入数据,或使用 get(key, callable) 方式加载。
// 创建 Cache
Cache<String, User> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
// 手动放入
cache.put("user-1", new User("张三"));
// 获取(可能为 null)
User user = cache.getIfPresent("user-1");
// 获取,不存在时通过 Callable 加载
User user2 = cache.get("user-2", () -> {
return userService.getById("user-2");
});2. LoadingCache(自动加载)
通过 CacheLoader 定义加载逻辑,缓存未命中时自动加载。
// 创建 LoadingCache
LoadingCache<String, User> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(new CacheLoader<String, User>() {
@Override
public User load(String userId) throws Exception {
// 缓存未命中时自动调用
return userService.getById(userId);
}
@Override
public Map<String, User> loadAll(Iterable<? extends String> keys) throws Exception {
// 批量加载(可选实现)
return userService.getByIds(keys);
}
});
// 获取单个(自动加载)
User user = cache.get("user-1");
// 批量获取
ImmutableMap<String, User> users = cache.getAll(Arrays.asList("user-1", "user-2"));容量配置
maximumSize - 最大条目数
Cache<String, Object> cache = CacheBuilder.newBuilder()
.maximumSize(1000) // 最多缓存 1000 个条目
.build();当缓存条目数达到上限时,会根据 LRU(最近最少使用)策略淘汰旧数据。
maximumWeight - 最大权重
适用于缓存对象大小不一的场景。
Cache<String, List<String>> cache = CacheBuilder.newBuilder()
.maximumWeight(10000) // 最大权重
.weigher((String key, List<String> value) -> value.size()) // 权重计算器
.build();
// 放入数据
cache.put("small", Arrays.asList("a", "b")); // 权重 2
cache.put("large", Arrays.asList("a", "b", "c", "d")); // 权重 4initialCapacity - 初始容量
Cache<String, Object> cache = CacheBuilder.newBuilder()
.initialCapacity(100) // 初始容量
.maximumSize(1000)
.build();过期配置
expireAfterWrite - 写入后过期
数据写入后经过指定时间过期,无论是否被访问。
Cache<String, Object> cache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES) // 写入 10 分钟后过期
.build();expireAfterAccess - 访问后过期
数据在最后一次访问后经过指定时间过期。
Cache<String, Object> cache = CacheBuilder.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES) // 最后访问 5 分钟后过期
.build();refreshAfterWrite - 写入后刷新
数据写入后经过指定时间触发刷新,但不会立即删除旧数据。
LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
.refreshAfterWrite(1, TimeUnit.MINUTES) // 写入 1 分钟后刷新
.build(new CacheLoader<String, Object>() {
@Override
public Object load(String key) {
return loadFromDB(key);
}
});注意
refreshAfterWrite 必须配合 CacheLoader 使用,且刷新是惰性的,只有在下次访问时才会触发。
组合使用
LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES) // 写入 10 分钟后过期
.refreshAfterWrite(1, TimeUnit.MINUTES) // 写入 1 分钟后刷新
.build(loader);引用配置
weakKeys - 弱引用键
Cache<Object, Object> cache = CacheBuilder.newBuilder()
.weakKeys() // 键使用弱引用
.build();当键对象没有其他强引用时,缓存条目可能被 GC 回收。
weakValues - 弱引用值
Cache<String, Object> cache = CacheBuilder.newBuilder()
.weakValues() // 值使用弱引用
.build();softValues - 软引用值
Cache<String, Object> cache = CacheBuilder.newBuilder()
.softValues() // 值使用软引用
.build();软引用在内存不足时才会被回收,适合做内存敏感的缓存。
引用类型对比
- 强引用:普通引用,不会被 GC 回收
- 软引用:内存不足时回收
- 弱引用:下次 GC 时回收
并发配置
concurrencyLevel - 并发级别
Cache<String, Object> cache = CacheBuilder.newBuilder()
.concurrencyLevel(16) // 并发级别,默认 4
.build();并发级别决定了内部分段锁的数量,值越大并发性能越好,但内存占用也越大。
完整配置示例
LoadingCache<String, User> cache = CacheBuilder.newBuilder()
// 容量配置
.initialCapacity(100)
.maximumSize(10000)
// 过期配置
.expireAfterWrite(30, TimeUnit.MINUTES)
.expireAfterAccess(10, TimeUnit.MINUTES)
.refreshAfterWrite(5, TimeUnit.MINUTES)
// 并发配置
.concurrencyLevel(8)
// 引用配置
.weakKeys()
.softValues()
// 统计配置
.recordStats()
// 移除监听
.removalListener(notification -> {
log.info("缓存移除: key={}, cause={}",
notification.getKey(), notification.getCause());
})
// 构建
.build(new CacheLoader<String, User>() {
@Override
public User load(String userId) {
return userService.getById(userId);
}
});小结
CacheBuilder 提供了丰富的配置选项,包括容量限制、过期策略、引用类型、并发级别等。合理配置这些参数可以让缓存更好地适应业务场景。
面试题预览
常见面试题
- expireAfterWrite 和 expireAfterAccess 有什么区别?
- refreshAfterWrite 的刷新机制是怎样的?
- weakKeys 和 softValues 分别适用于什么场景?
