Guava Cache
Guava Cache 是一种非常优秀的本地缓存解决方案,提供了基于容量,时间和索引的缓存回收方式。
为什么要使用本地缓存
- 相对于本地 I/O 来说:速度快、效率高;
- 相对于 Redis 来说:Redis 虽然优秀,但受限于网卡等原因,远水解不了近渴;
Guava Cache 的使用场景
- 愿意消耗一些内存空间来提升速度,比如做报表的时候,把报表用到的数据,从 MySQL 中查出来,放到 Guava Cache 中,然后在内存中做计算,完了在返回给客户端;
- 预料到某些键会被多次查询;
- 缓存中存放的数据总量不会超出内存容量;
Guava Cache 缓存的两种加载方式
都是利用 CacheBuilder 的 builder 模式来构建。
CacheLoader
- CacheLoader 是按 key 统一加载,所有取不到的数据,则统一智行一种 load 逻辑;
Callable
- Callable 方法允许在 get 的时候指定 key;
如何使用 Guava Cache ?
- 设置缓存容量;
- 设置超时时间:缓存什么时候过期,过期以后数据怎么处理;
- 提供移除监听器:在数据移除的时候,会收到通知;
- 提供缓存加载器:缓存是开机加载,还是手动加载,还是自动加载是由缓存加载器设置的;
- 构建缓存:直接使用代码的方式构建缓存;
Guava Cache 中一些关键的类
CacheBuilder
- 构建缓存的入口,指定缓存配置参数并初始化本地缓存;
- CacheBuilder 在 build 方法中,会把前面设置的参数,全部传递给 LocalCache,它自己实际不参与任何计算;这种初始化参数的方式值得借鉴,代码简洁宜易读;
CacheLoader | 抽象类
- 用户从数据源加载数据,定义 load、reload、loadAll 等操作;
Cache | 接口
- 定义 put、get、invalidate 等操作,这里只有缓存增删改的操作,没有数据加载的操作;
AbstractCache | 抽象类
- 实现 Cache 接口;
- 其中批量操作都是循环执行单词行为,而单次行为都没有具体定义;
LoadingCache | 接口
- 继承自 Cache;
- 定义 get、getUnchecked、getAll 等操作,这些操作都会从数据源 load 数据;
AbstractLoadingCache | 抽象类
- 继承自 AbstractCache,实现 LoadingCache 接口;
LocalCache | 类
- 整个 Guava Cache 的核心类,包含了 Guava Cache 的数据结构,以及基本的缓存操作方法;
LocalManualCache | LocalCache 静态内部类,实现 Cache 接口
- 其内部的增删改操作,全部调用成员变量 localCache(LocalCache)类型的相应方法;
Guava Cache 缓存回收的三种方式
按容量回收
- maximumSize(long):当缓存中的操作超过指定值,会把超过容量的数据回收掉;
定时回收
- expireAfterAccess(long, TimeUnit):缓存项在执行时间内没有被读或写,则回收;
- expireAfterWrite(long, TimeUnit):缓存项在给定的时间内没有被写访问,则回收;
基于引用回收
- CacheBuilder.weakKeys():使用弱引用存储 key;
- CacheBuilder.weakValues():使用弱引用存储 value;
- CacheBuilder.softValues():使用软引用存储 value;
Guava Cache 的缓存清除
- 常规 remove、clear 等操作;
- Removal Listener:通过 CacheBuilder.removalListener(RemovalListener) 方法添加一个监听器,当数据清除的时候,RemovalListener 会收到一个通知,通知中指定要清除的 key 和 value;
Guava Cache 的缓存信息统计
- 通过 CacheBuilder.recordStats() 方法,可以对 Guava Cache 进行缓存统计工作,可以统计一下信息:
- hitRate():返回查询的命中率;
- averageLoadPenalty():加载新值时的平均耗时;
- evictionCount():缓存回收的数量;