Guava Cache自动加载异步刷新代码实现

public interface ILocalCache{
    /**
     * 从缓存中获取数据
     * @param key
     * @return value
     */
    public V get(K key);
}


/**
* @Description:  用于初始化cache的参数及其缺省值
*/
public abstract class AbstractLoadingCache {
    private static final Logger logger= LoggerFactory.getLogger(AbstractLoadingCache.class);
    /**
     * 最大缓存条数。子类在构造方法中调用setMaximumSize(int size)来更改
     */
    protected int maximumSize = 10000;
    /**
     * 当缓存项在指定的时间段内没有被读或写就会被回收。子类在构造方法中调用setExpireAfterAccessDuration(int duration)来更改
     */
    protected int expireAfterAccessDuration = 60;
    /**
     * 当缓存项在指定的时间段内没有更新就会被回收。子类在构造方法中调用setExpireAfterWriteDuration(int duration)来更改
     */
    protected int expireAfterWriteDuration = 30;
    /**
     * 数据存在时长,子类在构造方法中调用setRefreshAfterWriteDuration(int duration)来更改
     */
    protected int refreshAfterWriteDuration = 10;
    /**
     * 时间单位(分钟)
     */
    protected TimeUnit timeUnit = TimeUnit.MINUTES;
    /**
     * Cache初始化或被重置的时间
     */
    protected Date resetTime;
    /**
     * 历史最高记录数
     */
    protected long highestSize = 0;
    /**
     * 历史最高记录时间
     */
    protected Date highestTime;
    /**
     * 初始化方法
     */
    protected abstract void init();
    /**
     * 获取当前类实例
     * @return cache
     */
    protected abstract com.google.common.cache.LoadingCache getCache();
    /**
     * 根据key从数据库或其他数据源中获取一个value,并被自动保存到缓存中。
     * @param key
     * @return value,连同key一起被加载到缓存中的。
     */
    protected abstract V fetchData(K key);

    /**
     * 从缓存中获取数据(第一次自动调用fetchData从外部获取数据),并处理异常
     * @param key
     * @return Value
     * @throws ExecutionException
     */
    protected V getValue(K key) throws ExecutionException {
        LoadingCache cache = getCache();
        V result = cache.get(key);
        long cacheSize = cache.size();
        if (cacheSize > highestSize) {
            highestSize = cacheSize;
            highestTime = new Date();
            logger.debug(getSimpleClassName()+":本地缓存{"+key+"}初始化成功!");
        }
        return result;
    }

    /**
     * 获取当前类的名字(含类全路径)
     * @return
     */
    protected String getClassName() {
        return this.getClass().getName();
    }

    /**
     * 获取当前类的名字(不含类全路径)
     * @return
     */
    protected String getSimpleClassName() {
        return this.getClass().getSimpleName();
    }

    /**
     * 获取当前缓存器历史最高缓存对象数量
     * @return long
     */
    public long getHighestSize() {
        return highestSize;
    }

    /**
     * 获取当前缓存器历史最高记录时间
     * @return
     */
    public Date getHighestTime() {
        return highestTime;
    }

    /**
     * 设置缓存初始化或者重置时间
     * @param resetTime
     */
    public void setResetTime(Date resetTime) {
        this.resetTime = resetTime;
    }
    public Date getResetTime() {
        return resetTime;
    }

    /**
     * 设置最大缓存条数
     * @param maximumSize
     */
    public void setMaximumSize(int maximumSize) {
        this.maximumSize = maximumSize;
    }
    public int getMaximumSize() {
        return maximumSize;
    }

    /**
     * 设置数据没有被访问时,存在时长
     * @param expireAfterAccessDuration
     */
    public void setExpireAfterAccessDuration(int expireAfterAccessDuration) {
        this.expireAfterAccessDuration = expireAfterAccessDuration;
    }
    public int getExpireAfterAccessDuration() {
        return expireAfterAccessDuration;
    }

    /**
     * 设置数据没有被更新时,存在时长
     * @param expireAfterWriteDuration
     */
    public void setExpireAfterWriteDuration(int expireAfterWriteDuration) {
        this.expireAfterWriteDuration = expireAfterWriteDuration;
    }
    public int getExpireAfterWriteDuration() {
        return expireAfterWriteDuration;
    }

    /**
     * 设置数据刷新时长
     * @param refreshAfterWriteDuration
     */
    public void setRefreshAfterWriteDuration(int refreshAfterWriteDuration) {
        this.refreshAfterWriteDuration = refreshAfterWriteDuration;
    }
    public int getRefreshAfterWriteDuration() {
        return refreshAfterWriteDuration;
    }
}


public abstract class CommonCache extends AbstractLoadingCache> implements ILocalCache> {
    private final Logger logger = LoggerFactory.getLogger(CommonCache.class);

    /**
     * 缓存容器的初始容量
     */
    private final static int initialCapacity = 512;
    /**
     * 并发级别,并发级别是指可以同时写缓存的线程数
     */
    private final static int concurrencyLevel = 4;

    /**
     * 自动加载缓存
     */
    public volatile LoadingCache> loadingCache;


    /**
     * guava线程池,用来产生ListenableFuture
     */
    private static ListeningExecutorService service = MoreExecutors.listeningDecorator(new ThreadPoolExecutor(2, 4, 10, TimeUnit.MINUTES, new ArrayBlockingQueue(2)));

    public CommonCache() {
    }


    public CommonCache(int expreTime) {
        // 最大缓存条数
        setMaximumSize(1024);
        // 数据刷新时长
        setRefreshAfterWriteDuration(expreTime);
        this.init();
    }


    /**
     * 初始化
     */
    @Override
    protected void init() {
        // 方式一
        loadingCache = CacheBuilder.newBuilder().maximumSize(maximumSize)
                // 设置缓存容器的初始容量
                .initialCapacity(initialCapacity)
                // 设置并发级别,并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(concurrencyLevel)
                // 每refreshAfterWriteDuration.timeUnit刷新数据
                .refreshAfterWrite(refreshAfterWriteDuration, timeUnit)
                .build(new CacheLoader>() {
                    @Override
                    public Map load(String key) throws Exception {
                        Map value = fetchData(key);
                        logger.debug(getSimpleClassName() + ":本地缓存{" + key + "}设置成功!");
                        return value;
                    }

                    @Override
                    public ListenableFuture> reload(final String key, final Map oldValue) {
                        logger.debug(Thread.currentThread().getName() + "......后台线程池异步reload刷新:" + key);
                        ListenableFuture> listenableFuture = service.submit(new Callable>() {
                            @Override
                            public Map call() {
                                Map value = fetchData(key);
                                logger.debug(Thread.currentThread().getName() + " success to mock query db...");
                                logger.debug(getSimpleClassName() + "后台线程池异步reload刷新:本地缓存{" + key + "}设置成功!");
                                return value;
                            }
                        });
                        Futures.addCallback(listenableFuture, new FutureCallback>() {
                            @Override
                            public void onSuccess(Map result) {
                                logger.error("CommonCache刷新缓存成功");
                            }

                            @Override
                            public void onFailure(Throwable e) {
                                logger.error("CommonCache刷新缓存异常", e);
                            }
                        });
                        return listenableFuture;
                    }
                });

        // 方式二
        loadingCache = CacheBuilder.newBuilder()
                .maximumSize(10)
                .refreshAfterWrite(7, TimeUnit.SECONDS)
                .build(CacheLoader.asyncReloading(new CacheLoader>() {
                    @Override
                    public Map load(String key) throws Exception {
                        logger.info("用户周期库存缓存超时时间-自动刷新:{}", key);
                        Map value = fetchData(key);
                        return value;
                    }
                }, Executors.newSingleThreadExecutor()));

        this.resetTime = new Date();
        this.highestTime = new Date();
    }

    /**
     * 重写获取实例方法获取当前类实例
     * @return cache
     */
    @Override
    public LoadingCache> getCache() {
        // 使用双重校验锁保证只有一个cache实例
        if (loadingCache == null) {
            synchronized (this) {
                if (loadingCache == null) {
                    this.init();
                }
            }
        }
        return loadingCache;
    }

    @Override
    public Map get(String key) {
        try {
            Map returnVal = getValue(key);
            return returnVal;
        } catch (ExecutionException e) {
            logger.error(getSimpleClassName() + ":执行异常-无法根据key={" + key + "}获取value,可能是数据库中无该记录。", e);
            return null;
        } catch (Exception e) {
            logger.error(getSimpleClassName() + ":无法根据key={" + key + "}获取value,可能是数据库中无该记录。", e);
            return null;
        }
    }


}

public class CodeMapMasCache extends CommonCache {
    private static final Logger logger = LoggerFactory.getLogger(CodeMapMasCache.class);
    private CodeMapMapper codeMapMapper;

    public CodeMapMasCache(CodeMapMapper codeMapMapper,int expreTime) {
        super(expreTime);
        this.codeMapMapper=codeMapMapper;
        loadingCache.put(BusinessConstant.CacheName.CodeMapMasCache, fetchData(null));
    }

    @Override
    protected Map fetchData(String key) {
        logger.debug(getSimpleClassName()+":本地缓存{"+"key"+"},正在从数据库中获取CodeMapMasDTO!获取时间:"+new Date());
        List codeMapInfoList = null;
        Map resultMap = new HashMap();
        try {
            codeMapInfoList = codeMapMapper.getAllCodeMapMasCache();
            for (CodeMapMasDTO codeMapMasDTO : codeMapInfoList) {
                resultMap.put(codeMapMasDTO.getCodeId(), codeMapMasDTO);
            }
        } catch (Exception e) {
            logger.error(getSimpleClassName() + ":===codeMapMapper.getAllCodeMapMasCache()===查询基础参数信息失败:", e);
        }
        return resultMap;
    }
}


@RefreshScope
@Configuration
public class CacheConfig {

    @Value("${codemap.cache.expires.time:10}")
    private int cacheExpiresTimeCodeMapMasCache;

    @Autowired(required = false)
    private CodeMapMapper codeMapMapper;
    @ConditionalOnExpression("${enable.codemap.cache:true}")
    @ConditionalOnBean(name = "codeMapMapper")
    @Bean
    public CodeMapMasCache codeMapMasCache(){
        return new CodeMapMasCache(codeMapMapper,cacheExpiresTimeCodeMapMasCache);
    }
}


@Component("guavaCacheService")
public class GuavaCacheServiceImpl implements GuavaCacheService {
    @Autowired(required = false)
    private CodeMapMasCache codeMapMasCache;
    @Autowired(required = false)
    private CodeMapMapper codeMapMapper;

    public Map getCodeMapMasCache() {
        Map codeMap = null;
        codeMap = codeMapMasCache.get(BusinessConstant.CacheName.CodeMapMasCache);
        return codeMap;
    }
    @Override
    public CodeMapMasDTO getCodeMapMasCacheSingle(String codeId) {
        CodeMapMasDTO codeMapMasDTO = null;
        Map map = this.getCodeMapMasCache();
        if (!CollectionUtils.isEmpty(map)) {
            codeMapMasDTO = map.get(codeId);
        }
        return codeMapMasDTO;
    }

    @Override
    public String getCodeMapMasCacheAttr1(String codeId) {
        CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);
        if (codeMapMasDTO != null) {
            return codeMapMasDTO.getAttribute1();
        }
        return null;
    }

    @Override
    public String getCodeMapMasCacheAttr2(String codeId) {
        CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);
        if (codeMapMasDTO != null) {
            return codeMapMasDTO.getAttribute2();
        }
        return null;
    }
    @Override
    public String getCodeMapMasCacheAttr3(String codeId) {
        CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);
        if (codeMapMasDTO != null) {
            return codeMapMasDTO.getAttribute3();
        }
        return null;
    }
    @Override
    public String getCodeMapMasCacheAttr4(String codeId) {
        CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);
        if (codeMapMasDTO != null) {
            return codeMapMasDTO.getAttribute4();
        }
        return null;
    }
}

你可能感兴趣的:(Redis,guava,java,缓存)