1. 什么是Guava cache
Guava是google开源的一个java框架包,其中有很多java工具包,Guava cache就是该框架包中的一个工具包,通过Guava cache包可以实现一些简单的缓存功能,可以将一些常用数据进行本地缓存。
2. Guava cache的案例使用
如当我们在做web开发的时候,有些固定数据更新的不频繁(如系统配置,模板数据等),为了提高系统性能,往往我们都会讲这些数据预加载到本地内存中,这样做可以减少系统访问数据库或读取本地文件数据的io操作时间,从而提高系统性能,降低数据库访问压力。
有这样一个场景,当web应用前台发生一个事件后需要系统给相应人员一个邮件通知,传统做法就是事件发生后调用通知功能,通知功能加载邮件模板数据(假设从数据库中查取),根据模板数据构建好邮件内容,在调用邮件通知功能发送邮件。在上面的应用场景中,我不谈你的事件调用如何去优化,如何去自动监听事件通知,我在这里只是想要一个不能在普通的场景来说明Guava cache的使用。在该场景中,通知功能查取邮件模板数据,这个步骤我们可以使用Guava cache将数据库数据查取到本地缓存中,这样做有两个好处,一是程序执行效益更高,直接访问内存数据,二是减少数据库访问压力,数据访问的时候就不在去频繁的访问数据库,只有cache不存在该数据的时候才去访问数据库,当然我们也可以根据自己的需要构建不同策略的cache。听起来有点像memcached,但是他比memcached轻量级多了,只需要在你的工程中加入一个jar,就可以像使用java API一样优雅。当然有的同学也会使用Map做缓存,但是Map做缓存是不可控的,如什么时候去刷新缓存,如何控制缓存策略等Map都不能提供这些功能,但Guava cache可以做到。听到这里是不是很心动啊,废话就不多了,下面就进入Guava cache正题。
Guava cache的缓存实现有两种方式:
(1) CacheLoader
(2) Callable
CacheLoder实现cache
package com.test.cache; /** * * @author xmong * 缓存配置常量接口 * */ public interface CacheConfig { //配置缓存条目的大小 public int maximumSize = 10; //配置数据加载到缓存后的刷新时间 public int refreshAfterWrite = 12; //配置数据加载到缓存后的移除时间 public int expireAfterWrite = 12; }
package com.test.cache; import java.util.concurrent.TimeUnit; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; /** * * @author xmong * 缓存存储的数据形式是key,value存储, * 为了使缓存比较通用,构建了一个抽象缓存父类,实现了一个缓存的模板 * key和value都使用泛型,使得子类可以缓存多种类型的数据 * 子类只需要实现getCacheData(key)方法,获取缓存数据即可 * @param <K> 缓存的key类 * @param <V> 缓存的value类 */ public abstract class AbstractLoadCache <K, V>{ /** * 数据缓存的构建 */ LoadingCache<K, V> cache = CacheBuilder.newBuilder() //设计缓存条目 .maximumSize(CacheConfig.maximumSize) //设计刷新时间 .refreshAfterWrite(CacheConfig.refreshAfterWrite, TimeUnit.HOURS) .build(new CacheLoader<K, V>(){ @Override public V load(K key) throws Exception { //执行缓存数据方法获取数据 return getData(key); } }); /** * 抽象方法,执行缓存数据 * @param key * @return */ public abstract V getData(K key); public LoadingCache<K, V> getCache() { return cache; } public void setCache(LoadingCache<K, V> cache) { this.cache = cache; } }
package com.test.cache; import java.util.concurrent.ExecutionException; /** * * @author xmong * 实现缓存数据类 */ public class CacheLoadData extends AbstractLoadCache<String, String> { @Override public String getData(String key) { //执行获取缓存数据方法体 System.out.println("getData method..."); //返回缓存数据 return "{key:"+key+",value:"+key+"}"; } public static void main(String[] args) { CacheLoadData cacheLoadData = new CacheLoadData(); try { /** * 循环多次调用缓存数据 */ for (int i = 0; i < 5; i++) { String str = cacheLoadData.cache.get("xmong"); System.out.println(str); } } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
执行结果:
getData method... {key:xmong,value:xmong} {key:xmong,value:xmong} {key:xmong,value:xmong} {key:xmong,value:xmong} {key:xmong,value:xmong}
从执行结果可以看出获取数据方法体只在第一次调用缓存的时候执行了一次,后面的多次的调用都是取缓存中的数据。
Callable实现cache
package com.test.cache; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; /** * * @author xmong * * @param <K> 缓存的key类 * @param <V> 缓存的value类 * @param <T> 缓存的数据参数类 */ public abstract class AbstractCallCache<K, V, T>{ /** * 创建缓存,设置缓存数据大小,设置缓存刷新时间 */ public Cache<K, V> cache = CacheBuilder.newBuilder() //缓存数据的条目 .maximumSize(CacheConfig.maximumSize) //根据键值对被创建或值被替换后多少时间后移除 .expireAfterWrite(CacheConfig.expireAfterWrite, TimeUnit.HOURS) .build(); /** * 根据key获取缓存数据 * @param key * @param t * @return */ public V getCacheData(final K key, final T t){ try { return cache.get(key, new Callable<V>() { public V call() throws Exception { //执行缓存数据方法 return getData(key, t); } }); } catch (ExecutionException e) { e.printStackTrace(); return null; } } /** * 抽象方法,根据参数加载数据 * @param key 缓存的key值 * @param t 加载数据的参数 * @return v */ public abstract V getData(K key, T t); public Cache<K, V> getCache() { return cache; } public void setCache(Cache<K, V> cache) { this.cache = cache; } }
package com.test.cache; /** * callcache的实现 * @author xmong * */ public class CacheCallData extends AbstractCallCache<String, String, String>{ @Override public String getData(String key, String t) { //执行获取缓存数据方法体 System.out.println("getData method..."); //返回缓存数据 return "{key:"+key+", value:"+key+", args:"+t+"}"; } public static void main(String[] args) { CacheCallData cacheCallData = new CacheCallData(); //循环多次调用缓存数据 for (int i = 0; i < 5; i++) { String str = cacheCallData.getCacheData("xmong", "args"); System.out.println(str); } } }
执行结果:
getData method... {key:xmong, value:xmong, args:args} {key:xmong, value:xmong, args:args} {key:xmong, value:xmong, args:args} {key:xmong, value:xmong, args:args} {key:xmong, value:xmong, args:args}
3.Guava cache相关说明