使用Guava 缓存的一次重构

简介:

前端时间看了一个guava教程, 然后项目中正好用到一个缓存的场景,于是用它的缓存重构了原来的代码。

背景

业务背景如下:有一个配置项rootStaff,一个耗时的运算从rootStaff下拿到一堆关联的staff,得到一个staffList。rootStaff可配置可更改,staffList可能会因为员工入职离职而变化,所以每天要更新一下计算结果。

根据以上业务背景,我们需要缓存rootStaff和staffList, 如果rootStaff和缓存不一样或者时间过期了就需要重新计算。

Guava缓存简析

guava缓存主要参考了这篇文章,这里就不再复述。

实现

在设计怎么构造和调用缓存时我还是想把它写成一个缓存工具类和一个业务类,虽然目前还没有第二个地方调用工具类,只是那样看上去会更清晰一些。

对缓存工具类,由于我想做成更业务无关些,所以打算采用get(K, Callable<V>)方法而不是build时候传入方法。然后缓存策略默认写死一天过期以后也可以方便的改。

另外由于我们缓存可能会因为外部配置项rootStaff改变而改变,我加了一个cleanCache的方法。

cache工具类实现如下:

public class StaffCacheUtil {

    public static StaffCacheUtil create() {
        return  new StaffCacheUtil();
    }

    private Cache<String, Object> staffCache;

    private StaffCacheUtil() {
        staffCache = CacheBuilder.newBuilder()
            .expireAfterWrite(1, TimeUnit.DAYS)
            .build();
        cleanCache();
    }

    public void cleanCache() {
        staffCache.cleanUp();
    }

    public Object get(String key, Callable<Object> callable) throws ExecutionException {
        return staffCache.get(key, callable);
    }

    public void put(String key, Object value) throws ExecutionException {
        staffCache.put(key, value);
    }

}

回到业务代码,先贴一下原来的实现:

String rootStaffId = diamondVariableManager.getVariable("topUserRemoveRootStaffId");

List<StaffInfoDO> userDList = new ArrayList<StaffInfoDO>();

if(rootStaffId != null){
    if(staffCache.get(activeIndex).get("rootStaffId") != null){
        long now = System.currentTimeMillis();
        long diff = now - time.get();
        if(!rootStaffId.equals(staffCache.get(activeIndex).get("rootStaffId")) ||                 diff > 86400*1000){
            if(time.compareAndSet(now - diff, now)){
                this.writeCache(rootStaffId);
            }
        }
} else {
    this.writeCache(rootStaffId);
}
    userDList = readCache();
}

List<String> userStaffIds = new ArrayList<String>();

这里staffCache是个map,readCache和writeCache去读和写map里某个key。

而用guava的代码是:

String rootStaffFromCache = (String)staffCacheUtil.get(ROOT_STAFF, new         Callable<Object>() {
    @Override
    public Object call() {
      staffCacheUtil.cleanCache();
      return rootStaffId;
    }
});

if (!rootStaffId.equals(rootStaffFromCache) ) {
    staffCacheUtil.cleanCache();
    staffCacheUtil.put(ROOT_STAFF, rootStaffId);
}
Object obj = staffCacheUtil.get(STAFF_KEY, new Callable<Object>() {
    @Override
    public Object call() {
        return getStaffData(rootStaffId);
    }
});
if (obj instanceof List && ((List)obj).get(0) instanceof StaffInfoDO) {
    userDList = (List<StaffInfoDO>)obj;
} else {
    logger.error("object from cache is not List<StaffInfoDO>");
}

这里用get(KEY, Callable<>)的方法使得代码看上去更符合_如果有缓存则返回;否则运算、缓存、然后返回_的模式,也省去了writecache和readcache的实现,对我来说习惯了匿名类的话逻辑会更清晰一些。

总结

这里主要用guava缓存做了一次尝试,感觉它能很方便的让我们设置缓存策略,而它的_如果有缓存则返回;否则运算、缓存、然后返回_也让我很涨姿势。

目录
相关文章
|
6月前
|
缓存 Java
【JAVA】基于Guava实现本地缓存
【JAVA】基于Guava实现本地缓存
95 0
|
4月前
|
缓存 Java Spring
Guava缓存工具类封装和使用
Guava缓存工具类封装和使用
104 0
|
4月前
|
存储 缓存 监控
Redis问题之如何使用Guava Cache来监控缓存的加载/命中情况
Redis问题之如何使用Guava Cache来监控缓存的加载/命中情况
|
4月前
|
存储 缓存 监控
Redis问题之使用Guava Cache相比自己设计本地缓存有哪些优势
Redis问题之使用Guava Cache相比自己设计本地缓存有哪些优势
|
6月前
|
存储 缓存 NoSQL
Guava 缓存详解及使用
Guava Cache 是`Google Fuava`中的一个内存缓存模块,用于将数据缓存到JVM内存中。 本文主要介绍下Guava缓存的配置详解及相关使用 缓存分为本地缓存与分布式缓存。本地缓存为了保证线程安全问题,一般使用`ConcurrentMap`的方式保存在内存之中,而常见的分布式缓存则有`Redis`,`MongoDB`等。
|
6月前
|
缓存 NoSQL Java
SpringBoot:第五篇 集成Guava(本地缓存+分布式缓存)
SpringBoot:第五篇 集成Guava(本地缓存+分布式缓存)
315 0
|
存储 缓存 监控
真正的缓存之王,Google Guava 只是弟弟(一)
前面刚说到Guava Cache,他的优点是封装了get,put操作;提供线程安全的缓存操作;提供过期策略;提供回收策略;缓存监控。当缓存的数据超过最大值时,使用LRU算法替换。这一篇我们将要谈到一个新的本地缓存框架:Caffeine Cache。它也是站在巨人的肩膀上-Guava Cache,借着他的思想优化了算法发展而来。 本篇博文主要介绍Caffine Cache 的使用方式,以及Caffine Cache在SpringBoot中的使用。
真正的缓存之王,Google Guava 只是弟弟(一)
|
存储 缓存 NoSQL
真正的缓存之王,Google Guava 只是弟弟(二)
真正的缓存之王,Google Guava 只是弟弟(二)
|
存储 缓存 JSON
Google Guava本地缓存的实战
Google Guava本地缓存的实战
657 0
Google Guava本地缓存的实战
|
缓存 Java
Guava之Supplier缓存使用示例
使用guava作内存缓存,大多数小伙伴应该都使用过,通过CacheBuilder创建LoadingCache一个kv格式的缓存,如果我们需要缓存的只是一个value呢? 针对这种场景,接下来介绍一种基于Supplier来实现的缓存方式
547 0