原文地址:http://www.xx566.com/detail/174.html
在之前Guava库学习:学习Guava Cache(二)Guava caches(1)_Cache以及Guava库学习:学习Guava Cache(二)Guava caches(2)_LoadingCache的 学习中,我们了解了Cache 和 LoadingCache,它们是Guava Cache缓存机制的基础接口,我们本篇即将学习的CacheBuilder类,通过建造者(Builder)模式为我们提供了一种获取Cache和 LoadingCache实例的方式,接下来,我们就开始Guava Cache系列:CacheBuilder的学习。
更多建造者模式,欢迎参阅:揭秘设计模式:建造者模式(Builder)的理解和学习
CacheBuilder提供了许多选项,我们可以选择部分来创建Cache实例,不需要列出所有的选项,这是Builder模式的魅力,接下来,我们通 过下面的一些例子,来了解如何在guava 中使用Cache缓存机制,第一个例子演示的是在缓存条目加载到缓存中后,我们如何指定条目失效:
LoadingCache<String, TradeAccount> tradeAccountCache = CacheBuilder.newBuilder() .expireAfterWrite(5L, TimeUnit.MINUTES) .maximumSize(5000L) .removalListener(new TradeAccountRemovalListener()) .ticker(Ticker.systemTicker()) .build(new CacheLoader<String, TradeAccount>() { @Override public TradeAccount load(String key) throws Exception { return tradeAccountService.getTradeAccountById(key); } });
上面的代码中,我们为如下所示的TradeAccount对象构造了一个LoadingCache实例:
public class TradeAccount { private String id; //ID private String owner; //所有者 private double balance; //余额 }
我们来简要的对第一个例子做一些说明:
首先,我们调用了expireAfterWrite方法,它可以自动的使缓存条目在指定的时间后失效,在本例中,是5分钟。
第二步,我们通过maximumSize方法,5000作为传入值,指定了缓存的最大大小,当缓存的大小逼近到最大值时,缓存中一些最近很少使用到的条目将会被移除,不一定在缓存大小达到最大值甚至超过最大值才移除。
我们注册了一个RemovalListener监听器实例,它可以在缓存中的条目被移除后接收通知,更多RemovalListener,我们将在Guava库学习:学习Guava Cache(七)中进行学习,敬请关注。
我们添加了一个Ticker实例,通过调用ticker方法,此方法提供了缓存条目过期的时间,纳秒级的精密度。
最后,我们调用了build方法,传入了一个新的CacheLoader实例,当缓存中的key存在,value不存在时,这个实例将被用来重新获取TradeAccount对象。
在接下来的实例中,我们来看看怎么使缓存条目失效,基于上一次条目被访问后所经过的时间:
LoadingCache<String, Book> bookCache = CacheBuilder.newBuilder() .expireAfterAccess(20L, TimeUnit.MINUTES) .softValues() .removalListener(new BookRemovalListener()) .build(new CacheLoader<String, Book>() { @Override public Book load(String key) throws Exception { return bookService.getBookByIsbn(key); } });
在这个例子中,我们对代码做了轻微的调整,我们来进行一下说明:
通过调用expireAfterAccess方法,我们指定了缓存中的条目在上一次访问经过20分钟后失效。
我们不再明确的指定缓存的最大值, 而是通过调用softValues()方法, 让JVM虚拟机将缓存中的条目包装成软引用对象,以限制的缓存大小。如果内存空间不足,缓存中的条目将会被移除。需要注意的是,哪些软引用可以被垃圾回收 是由JVM内部进行的LRU计算所决定的。
最后,我们添加了一个类似的RemovalListener监听器,用于处理缓存中value值不存在的条目。
来看最后一个例子,我们将介绍如何自动的刷新LongCache缓存中的条目值:
LoadingCache<String, TradeAccount> tradeAccountCache = CacheBuilder.newBuilder() .concurrencyLevel(10) .refreshAfterWrite(5L, TimeUnit.SECONDS) .ticker(Ticker.systemTicker()) .build(new CacheLoader<String, TradeAccount>() { @Override public TradeAccount load(String key) throws Exception { return tradeAccountService.getTradeAccountById(key); } });
在上面的例子中,我们再次做了细微的调整,说明如下:
通过调用concurrencyLevel方法,我们设置了并发更新操作的数量为10,如果不设置的话,默认值为4。
不再明确的移除缓存条目,而是通过refreshAfterWrite方法在给定的时间过去后,刷新缓存中的条目值,当缓存条目的值被调用并且已经超过了设置的时间,刷新缓存的触发器将处于活动状态。
我们添加了纳秒级别的Ticker,以刷新那些符合条件的条目值。
最后,通过调用build方法,我们指定了需要使用的Loader。
代码地址:http://git.oschina.net/realfighter/xx566-diary/blob/master/src/guava/CacheBuilderTest.java
这里推荐一篇文章,对CacheBuilder的机制有比较深入的讲解:Guava缓存器源码分析——CacheBuilder,可以学习下。