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

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


/**
* @Description:  用于初始化cache的参数及其缺省值
*/
public abstract class AbstractLoadingCache<K,V> {
    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<K, V> 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<K, V> 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<T, V> extends AbstractLoadingCache<String, Map<String, V>> implements ILocalCache<String,
        Map<String, V>> {
    private final Logger logger = LoggerFactory.getLogger(CommonCache.class);

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

    /**
     * 自动加载缓存
     */
    public volatile LoadingCache<String, Map<String, V>> loadingCache;


    /**
     * guava线程池,用来产生ListenableFuture
     */
    private static ListeningExecutorService service = MoreExecutors.listeningDecorator(new ThreadPoolExecutor(2, 4, 10, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(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<String, Map<String, V>>() {
                    @Override
                    public Map<String, V> load(String key) throws Exception {
                        Map<String, V> value = fetchData(key);
                        logger.debug(getSimpleClassName() + ":本地缓存{" + key + "}设置成功!");
                        return value;
                    }

                    @Override
                    public ListenableFuture<Map<String, V>> reload(final String key, final Map<String, V> oldValue) {
                        logger.debug(Thread.currentThread().getName() + "......后台线程池异步reload刷新:" + key);
                        ListenableFuture<Map<String, V>> listenableFuture = service.submit(new Callable<Map<String, V>>() {
                            @Override
                            public Map<String, V> call() {
                                Map<String, V> 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<Map<String, V>>() {
                            @Override
                            public void onSuccess(Map<String, V> 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<String, Map<String, V>>() {
                    @Override
                    public Map<String, V> load(String key) throws Exception {
                        logger.info("用户周期库存缓存超时时间-自动刷新:{}", key);
                        Map<String, V> value = fetchData(key);
                        return value;
                    }
                }, Executors.newSingleThreadExecutor()));

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

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

    @Override
    public Map<String, V> get(String key) {
        try {
            Map<String, V> 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<CodeMapMapper,CodeMapMasDTO> {
    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<String,CodeMapMasDTO> fetchData(String key) {
        logger.debug(getSimpleClassName()+":本地缓存{"+"key"+"},正在从数据库中获取CodeMapMasDTO!获取时间:"+new Date());
        List<CodeMapMasDTO> codeMapInfoList = null;
        Map<String, CodeMapMasDTO> resultMap = new HashMap<String, CodeMapMasDTO>();
        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<String, CodeMapMasDTO> getCodeMapMasCache() {
        Map<String, CodeMapMasDTO> codeMap = null;
        codeMap = codeMapMasCache.get(BusinessConstant.CacheName.CodeMapMasCache);
        return codeMap;
    }
    @Override
    public CodeMapMasDTO getCodeMapMasCacheSingle(String codeId) {
        CodeMapMasDTO codeMapMasDTO = null;
        Map<String, CodeMapMasDTO> 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;
    }
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值