public class GuavaCacheDemo {
private Cache<String, Man> cache;
private LoadingCache<String,Man> loadingCache;
private RemovalListener<String, Man> removalListener;
/**
* 注册移除key-value监听器
*/
public void init(){
removalListener = new RemovalListener<String, Man>(){
@Override
public void onRemoval(RemovalNotification<String, Man> notification) {
Logger logger = LoggerFactory.getLogger("RemovalListener");
logger.info("被移除的key={}", notification.getKey());
//可以在监听器中获取key,value,和删除原因
logger.info("被移除的value={}", notification.getValue());
logger.info("被移除的cause={}", notification.getCause());
//EXPLICIT、REPLACED、COLLECTED、EXPIRED、SIZE
}};
//可以使用RemovalListeners.asynchronous方法将移除监听器设为异步方法
//removalListener = RemovalListeners.asynchronous(removalListener, new ThreadPoolExecutor(1,1,1000, TimeUnit.MINUTES,new ArrayBlockingQueue<Runnable>(1)));
}
/**
* 初始化loadingCache
*/
public void initLoadingCache() {
//指定一个如果数据不存在获取数据的方法
CacheLoader<String, Man> cacheLoader = new CacheLoader<String, Man>() {
@Override
public Man load(String key) throws Exception {
//模拟mysql操作
Logger logger = LoggerFactory.getLogger("LoadingCache");
logger.info("LoadingCache测试 从mysql加载缓存ing...(2s)");
Thread.sleep(2000);
logger.info("LoadingCache测试 从mysql加载缓存成功");
Man tmpman = new Man();
tmpman.setId(key);
tmpman.setName("其他人");
if (key.equals("001")) {
tmpman.setName("张三");
return tmpman;
}
if (key.equals("002")) {
tmpman.setName("李四");
return tmpman;
}
return tmpman;
}
};
//缓存数量为1,为了展示缓存删除效果
loadingCache = CacheBuilder.newBuilder().
//设置2分钟没有获取将会移除数据
expireAfterAccess(2, TimeUnit.MINUTES).
//设置2分钟没有更新数据则会移除数据
expireAfterWrite(2, TimeUnit.MINUTES).
//每1分钟刷新数据
refreshAfterWrite(1,TimeUnit.MINUTES).
//设置key为弱引用
weakKeys().
maximumSize(1).
removalListener(removalListener).
build(cacheLoader);
}
//获取数据,如果不存在返回null
public Man getIfPresentloadingCache(String key){
return loadingCache.getIfPresent(key);
}
//获取数据,如果数据不存在则通过cacheLoader获取数据,缓存并返回
public Man getCacheKeyloadingCache(String key){
try {
return loadingCache.get(key);
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
//直接向缓存put数据
public void putloadingCache(String key,Man value){
Logger logger = LoggerFactory.getLogger("LoadingCache");
logger.info("put key :{} value : {}",key,value.getName());
loadingCache.put(key,value);
}
public void initDefault() {
cache = CacheBuilder.newBuilder().
expireAfterAccess(2, TimeUnit.MINUTES).
expireAfterWrite(2, TimeUnit.MINUTES).
weakKeys().
maximumSize(1).
removalListener(removalListener).
build();
}
public Man getIfPresentCache(String key){
return cache.getIfPresent(key);
}
public Man getCacheKeyCache(final String key) throws ExecutionException {
return cache.get(key, new Callable<Man>() {
@Override
public Man call() throws Exception {
//模拟mysql操作
Logger logger = LoggerFactory.getLogger("Cache");
logger.info("Cache测试 从mysql加载缓存ing...(2s)");
Thread.sleep(2000);
logger.info("Cache测试 从mysql加载缓存成功");
Man tmpman = new Man();
tmpman.setId(key);
tmpman.setName("其他人");
if (key.equals("001")) {
tmpman.setName("张三");
return tmpman;
}
if (key.equals("002")) {
tmpman.setName("李四");
return tmpman;
}
return tmpman;
}
});
}
}
缓存加载:CacheLoader、Callable、显示插入(put)
缓存回收:LRU,定时(expireAfterAccess,expireAfterWrite),软弱引用,显示删除(Cache接口方法invalidate,invalidateAll)
监听器:CacheBuilder.removalListener(RemovalListener)
清理缓存时间:只有在获取数据时才或清理缓存LRU,使用者可以单起线程采用Cache.cleanUp()方法主动清理。
刷新:主动刷新方法LoadingCache.referesh(K)
信息统计:CacheBuilder.recordStats() 开启Guava Cache的统计功能。Cache.stats() 返回CacheStats对象。(其中包括命中率等相关信息)
获取当前缓存所有数据:cache.asMap(),cache.asMap().get(Object)会刷新数据的访问时间(影响的是:创建时设置的在多久没访问后删除数据)
ManualCache可以在get时动态设置获取数据的方法,而LoadingCache可以定时刷新数据。如何取舍?我认为在缓存数据有很多种类的时候采用第一种cache。而数据单一,数据库数据会定时刷新时采用第二种cache。