作用
- 缓存
- 异步持续更新缓存
构造LoadingCache对象
LoadingCache<Integer, String> loadingCache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.SECONDS)
.refreshAfterWrite(500, TimeUnit.MILLISECONDS)
.maximumSize(10) // 缓存最大数量
.removalListener((RemovalListener<Integer, String>) (integer, s, removalCause) -> {
System.out.println("key:" + integer + " value:" + s + " cause:"+removalCause);
})
.build(new CacheLoader<Integer, String>() {
@Nullable
@Override
public String load(@NonNull Integer i) throws Exception {
return i.toString();
}
@Override
public Map<Integer, String> loadAll(Iterable<? extends Integer> keys) {
Map<Integer, String> map = new HashMap<>();
for (Integer i : keys) {
map.put(i, i.toString());
}
return map;
}
});
复制代码
参数解析
- expireAfterWrite:失效策略,类似参数还有expireAfterAccess,key的缓存时间到期以后并不会被立即删除,caffeine使用惰性删除的策略,在LoadingCache被修改,如添加,更新等,或者该失效的key被访问的时候才会删除。
- refreshAfterWrite:刷新策略,设置为比写入时间小可以保证缓存永不失效,对于某些场景,比如请求频率低但是耗时长的业务来说,自动刷新能够显著提升效率和体验
- maximumSize:缓存的item的最大数目,如果超过这个数, caffeine将根据Window TinyLfu策略淘汰一些key,类似的参数还有maximumWeight,示例代码如下,设置maximumWeight的同时,要设置weigher参数,根据key生成对应的weight,如果累计weight达到了maximumWeight,将会进行key的淘汰,淘汰策略与maximumSize一样,与weight无关。另外,maximumSize与maximumWeight不能同时使用,否则会报IllegalStateException。
LoadingCache<Integer, String> weightLoadingCache = Caffeine.newBuilder()
.maximumWeight(1000)
.weigher((Weigher<Integer, String>) (integer, s) -> integer)
.build(new CacheLoader<Integer, String>() {
@Nullable
@Override
public String load(@NonNull Integer integer) throws Exception {
return null;
}
});
复制代码
- removalListener:当缓存被移除的时候执行的策略,例如打日志等
- build参数CacheLoader:用于refresh时load缓存的策略,根据具体业务而定,建议在实现load方法的同时实现loadAll方法loadAll方法适用于批量查缓存的需求,或者刷新缓存涉及到网络交互等耗时操作。比如你的缓存数据需要从redis里获取,如果不实现loadAll,则需要多次load操作,也就需要多次redis交互,非常耗时,而实现loadAll,则可以在loadAll里向redis发送一条批量请求,显著降低网络交互次数和时间,显著提升效率。
注意事项
caffeine是不缓存null值的,如果在load的时候返回null,caffeine将会把对应的key从缓存中删除,同时,loadAll返回的map里是不可以包含value为null的数据,否则将会报NullPointerException
常用方法
V get(@NonNull K key)
返回给定的key在LoadingCache中的数据,如果cache中没有该key,将调用CacheLoader的load方法去load数据,如果load不到数据,将返回null。
Map<K, V> getAll(@NonNull Iterable<? extends K> keys)
返回keys中的key的缓存数据,组合成map,如果某个key或某些key在缓存中不存在,将会调用loadAll去load数据,loadAll仍然无法load到数据的key,将不会put到返回的map里。
void refresh(@NonNull K key)
明确地更新某个key,异步调用load
put,putAll
这两个方法明确地添加缓存,对于LoadingCache来说,实际上是不需要调用,因为在get和getAll的时候会自动load缓存,如果缓存不存在。