当前位置: 代码迷 >> 综合 >> Guava Cache自动加载异步刷新代码实现
  详细解决方案

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

热度:74   发布时间:2024-01-26 11:20:55.0
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();}/*** 初始化*/@Overrideprotected void init() {// 方式一loadingCache = CacheBuilder.newBuilder().maximumSize(maximumSize)// 设置缓存容器的初始容量.initialCapacity(initialCapacity)// 设置并发级别,并发级别是指可以同时写缓存的线程数.concurrencyLevel(concurrencyLevel)// 每refreshAfterWriteDuration.timeUnit刷新数据.refreshAfterWrite(refreshAfterWriteDuration, timeUnit).build(new CacheLoader<String, Map<String, V>>() {@Overridepublic Map<String, V> load(String key) throws Exception {Map<String, V> value = fetchData(key);logger.debug(getSimpleClassName() + ":本地缓存{" + key + "}设置成功!");return value;}@Overridepublic 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>>() {@Overridepublic 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>>() {@Overridepublic void onSuccess(Map<String, V> result) {logger.error("CommonCache刷新缓存成功");}@Overridepublic 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>>() {@Overridepublic 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*/@Overridepublic LoadingCache<String, Map<String, V>> getCache() {// 使用双重校验锁保证只有一个cache实例if (loadingCache == null) {synchronized (this) {if (loadingCache == null) {this.init();}}}return loadingCache;}@Overridepublic 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));}@Overrideprotected 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")@Beanpublic 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;}@Overridepublic CodeMapMasDTO getCodeMapMasCacheSingle(String codeId) {CodeMapMasDTO codeMapMasDTO = null;Map<String, CodeMapMasDTO> map = this.getCodeMapMasCache();if (!CollectionUtils.isEmpty(map)) {codeMapMasDTO = map.get(codeId);}return codeMapMasDTO;}@Overridepublic String getCodeMapMasCacheAttr1(String codeId) {CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);if (codeMapMasDTO != null) {return codeMapMasDTO.getAttribute1();}return null;}@Overridepublic String getCodeMapMasCacheAttr2(String codeId) {CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);if (codeMapMasDTO != null) {return codeMapMasDTO.getAttribute2();}return null;}@Overridepublic String getCodeMapMasCacheAttr3(String codeId) {CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);if (codeMapMasDTO != null) {return codeMapMasDTO.getAttribute3();}return null;}@Overridepublic String getCodeMapMasCacheAttr4(String codeId) {CodeMapMasDTO codeMapMasDTO = this.getCodeMapMasCacheSingle(codeId);if (codeMapMasDTO != null) {return codeMapMasDTO.getAttribute4();}return null;}
}

 

  相关解决方案