场景:我们对于需要大量计算的场景,希望将结果缓存起来,然后我们一起来实现一个缓存服务。即对于一个相同的输入,它的输出是不变的(也可以短时间不变)。
实现说明:这里实现采用GuavaCache+装饰器模式。
首先设计一个缓存服务接口。
public interface CacheableService<I, O> { /** * 计算服务 * @param i * @return * @throws Exception */ O doService(I i) throws Exception; }
这里定义了一个缓存服务接口,这里的key和Hashmap的key一样,需要覆写equals和hashcode方法。
public class CacheableServiceWrapper<I , O> implements CacheableService<I, O>, GlobalResource { /** * 日志 */ private final static Logger LOGGER = LoggerFactory .getLogger(CacheableServiceWrapper.class); /** * 缓存大小 */ private int MAX_CACHE_SIZE = 20; /** * 出现异常的时候重试,默认不重试 */ private boolean retryOnExp = false; /** * 重试次数,默认为0,即不重试 */ private int retryTimes = 0; /** * 默认30分钟 */ private long expireTimeWhenAccess = 30 * 60; /** * 缓存 */ private LoadingCache<I, Future<O>> cache = null; private CacheableService<I, O> cacheableService = null; /** * Calculate o. * * @param i the * @return the o * @throws Exception the exception */ public O doService(final I i) throws Exception { Assert.notNull(cacheableService, "请设置好实例"); int currentTimes = 0; while (currentTimes <= retryTimes) { try { Future<O> oFuture = cache.get(i); return oFuture.get(); } catch (Exception e) { if (!retryOnExp) { throw e; } currentTimes++; LoggerUtils.info(LOGGER, "第", currentTimes, "重试,key=", i); } } throw new Exception("任务执行失败"); } /** * 提交计算任务 * * @param i * @return */ private Future<O> createTask(final I i) { Assert.notNull(cacheableService, "请设置好实例"); LoggerUtils.info(LOGGER, "提交任务,key=", i); LoggerUtils.info(LOGGER, "当前cache=", JSON.toJSONString(cache)); Future<O> resultFuture = THREAD_POOL.submit(new Callable<O>() { public O call() throws Exception { return cacheableService.doService(i); } }); return resultFuture; } /** * 构造函数 */ public CacheableServiceWrapper(CacheableService<I, O> cacheableService, int maxCacheSize, long expireTime) { this.cacheableService = cacheableService; this.MAX_CACHE_SIZE = maxCacheSize; this.expireTimeWhenAccess = expireTime; cache = CacheBuilder.newBuilder().maximumSize(MAX_CACHE_SIZE) .expireAfterAccess(expireTimeWhenAccess, TimeUnit.SECONDS) .build(new CacheLoader<I, Future<O>>() { public Future<O> load(I key) throws ExecutionException { LoggerUtils.warn(LOGGER, "get Element from cacheLoader"); return createTask(key); } ; }); } /** * 构造函数 */ public CacheableServiceWrapper(CacheableService<I, O> cacheableService) { this.cacheableService = cacheableService; cache = CacheBuilder.newBuilder().maximumSize(MAX_CACHE_SIZE) .expireAfterAccess(expireTimeWhenAccess, TimeUnit.SECONDS) .build(new CacheLoader<I, Future<O>>() { public Future<O> load(I key) throws ExecutionException { LoggerUtils.warn(LOGGER, "get Element from cacheLoader"); return createTask(key); } ; }); } /** * Setter method for property <tt>retryTimes</tt>. * * @param retryTimes value to be assigned to property retryTimes */ public void setRetryTimes(int retryTimes) { this.retryTimes = retryTimes; } /** * Setter method for property <tt>retryOnExp</tt>. * * @param retryOnExp value to be assigned to property retryOnExp */ public void setRetryOnExp(boolean retryOnExp) { this.retryOnExp = retryOnExp; } }