一.概述
缓存是Web开发中不可或缺的一个重要工具。说起缓存大家想到更多的是redis、memcached等key-value存储系统,他们将数据存储在内存,并支持分布式部署,被广泛使用。但有时我们不想在项目引入他们(相对来说他们是“重”的,如果没有更充分的理由,应避免加大系统的复杂性),同时我们要缓存的数据量并不会对当前服务器的内存造成影响。这时我们就可以考虑使用本地缓存,即将需要频繁查询的数据放到JVM内存里。而google guava提供的Cache就是一个做本地缓存的不错选择。
Guava官网介绍说,有以下几种情况的化可以考虑使用Guava Cache:
- 愿意消耗一些内存空间来提升速度
- 预料到某些键会被多次查询
- 缓存中存放的数据总量不会超出内存容量
二.Guava Cache的使用
LoadingCache是Cache的一个子接口。顾名思义,它允许用户设置一个载入方法。当缓存未命中时,通过该方法获取key对应的value并放入Cache。因为LoadingCache用的比较多,下面介绍一下它的用法。
2.1 LoadingCache的定义
LoadingCache<Integer, String> numberTranlation = CacheBuilder.newBuilder()
.maximumSize(10) //最大能缓存的容量
.expireAfterAccess(1, TimeUnit.DAYS) //过期策略:1天没被访问后过期
.recordStats() //开启统计功能
.build(new CacheLoader<Integer, String>() {
@Override
public String load(Integer integer) throws Exception {
return NumberTranslationApi.translation(integer);
}
});
LoadingCache使用一个构造器CacheBuilder构造,使用了构建者模式,其每个方法的返回值都是该CacheBuilder本身,直到使用了build方法,才返回一个LoadingCache。
CacheBuilder中提供了很多方法用于对LoadingCache进行设置:
容量设置:
//设置缓存的最大容量,添加元素时若发现容量已满则按一定规则删除之前的元素
maximumSize(100);
过期时间设置:
//过期时间设置,如果一个元素1天内没有被访问则失效
expireAfterAccess(1, TimeUnit.DAYS);
//过期时间设置,如果一个元素1天内没有被写入更新则失效
expireAfterWrite(1,TimeUnit.DAYS);
开启数据统计:
recordStats() ;
另外,开启数据统计后要想打印统计结果可以调用Cache.stats()方法。
需要给build方法传入一个CacheLoader,需重载其load方法。load方法的作用是在通过get方法从LoadingCache获取不到值时去加载该值并放入缓存。
这种构造方式非常适用于需要从其它接口、方法获取value值的情况,在CacheLoader中的load定义了如何从接口、方法中得到value值。
2.2 使用get方法从缓存中取值
//numberTranlation如2.1节定义
numberTranlation.get(1);
numberTranlation.getIfPresent(1);
使用get方法获取缓存中的值,如果缓存中不存在则通过CacheLoader.load方法进行加载后返回。
与get方法略有差别的是getIfPresent方法,该方法在缓存没命中时返回null,且不会去调用CacheLoader.load方法加载数据。
关于这两个方法的区别,看一下下面的例子就理解了:
numberTranlation.getIfPresent(1); //返回null
numberTranlation.get(1); //返回“one”,执行了load方法载入
numberTranlation.getIfPresent(1); //返回"one"
numberTranlation.get(1); //返回“one”
2.3 使用get方法的带Callable参数版本覆盖load方法
int key = 20;
Cache.numberTranlation.get(key, new Callable<String>() {
@Override
public String call() throws Exception {
return NumberTranslationApi.translation(key);
}
});
Guava的Cache接口中还定义了get的一个带Callable的版本,使用该方法时,如果缓存未命中则使用该Callable进行value计算,并载入到缓存里。
注意:
对于普通Cache也是使用CacheBuilder构造的,只是不需要给builder传入CacheLoader。
而其它maximumSize等方法也和LoadingCache一样使用。换句话说LoadingCache只是
多了一个CacheLoader来规定未命中缓存时的操作。
另外需要注意的是下面的get(key,new Callable()……)方法,也适用于普通的Cache。即
对于普通Cache也可以定义未命中时的载入操作。
三.学习资料
下面附上google guava缓存部门的源码在github上的地址,方便大家去学习。
https://github.com/google/guava/tree/master/guava/src/com/google/common/cache
如果本文对您有帮助,欢迎关注我的原创微信公众号“Java技术小站”第一时间接收我的更多文章