Guava Cache做本地缓存那些事

一.概述

缓存是Web开发中不可或缺的一个重要工具。说起缓存大家想到更多的是redis、memcached等key-value存储系统,他们将数据存储在内存,并支持分布式部署,被广泛使用。但有时我们不想在项目引入他们(相对来说他们是“重”的,如果没有更充分的理由,应避免加大系统的复杂性),同时我们要缓存的数据量并不会对当前服务器的内存造成影响。这时我们就可以考虑使用本地缓存,即将需要频繁查询的数据放到JVM内存里。而google guava提供的Cache就是一个做本地缓存的不错选择。

Guava官网介绍说,有以下几种情况的话可以考虑使用Guava Cache:

  1. 愿意消耗一些内存空间来提升速度
  2. 预料到某些键会被多次查询
  3. 缓存中存放的数据总量不会超出内存容量

二.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也可以定义未命中时的载入操作。

三.学习资料

本文只是对Guava Cache的基本使用做了介绍,要想了解其实现原理,请移步Guava Cache实现原理浅析

下面附上google guava缓存部门的源码在github上的地址,方便大家去学习。
https://github.com/google/guava/tree/master/guava/src/com/google/common/cache

关注公众号,第一时间接收我更多文章
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/vxzhg/article/details/102600452