前言:由于用户系统重构存在新老版本,网关对部分数据进行路径写死,所以为了避免频繁请求接口对网关日志记录进行本地缓存处理,学习过程中有Cache和LoadingCache两种模式,一番测试下都可以正常使用,特此记录
准备工作
- 添加依赖
<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
Cache的使用
构造之后直接使用cache.get以及cache.put把它当成一个map来使用就行,也可以自己封装一个工具类来使用,这里不做过多赘述。
LoadingCache 的使用
- 使用前先介绍下三种过期规则
expireAfterAccess: 当缓存项在指定的时间段内没有被读或写就会被回收。
expireAfterWrite:当缓存项在指定的时间段内没有更新就会被回收(移除key),需要等待获取新值才会返回。
refreshAfterWrite:当缓存项上一次更新操作之后的多久会被刷新。第一个请求进来,执行load把数据加载到内存中(同步过程),指定的过期时间内比如10秒,都是从cache里读取数据。过了10秒后,没有请求进来,不会移除key。再有请求过来,才则执行reload,在后台异步刷新的过程中,如果当前是刷新状态,访问到的是旧值。刷新过程中只有一个线程在执行刷新操作,不会出现多个线程同时刷新同一个key的缓存。在吞吐量很低的情况下,如很长一段时间内没有请求,再次请求有可能会得到一个旧值(这个旧值可能来自于很长时间之前),这将会引发问题。(可以使用expireAfterWrite和refreshAfterWrite搭配使用解决这个问题)
- 由于我的需求是5分钟加载(load方法)一次,所以我仅仅使用了expireAfterWrite
private LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES) // 设置访问后5min的过期时间
.initialCapacity(100)
.maximumSize(4000)
.build(new CacheLoader<String, String>() {
@Override // 加载缓存的方法, 必须实现
public String load(String key) throws Exception{
return selector();
}
});
/**
* 版本选择器-老版tu和新版ks用户体系选择
* @return
*/
private String selector(){
// 为空或者异常或者"value":"0" 都为false
boolean succ = false;
try {
succ = ksService.versionSelector();
} catch (Exception e) {
}
return succ ? "/ks-prj" : "/tu-prj";
}
public String getAppend(){
try {
// 获取本地缓存设置的值,当前缓存定制化,随意传参
return cache.get("1");
} catch (ExecutionException e) {
log.error("本地缓存异常:{}",e);
}
return selector();
}
测试
// 随机设置selector的值,验证缓存是否生效和过期时间是否重新加载
public String selector() {
Random random = new Random();
return String.valueOf(random.nextInt());
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
CacheBuildUtils utils = new CacheBuildUtils();
while (true){
String s = utils.dataLoadingCache.get("111");
System.out.println(s);
Thread.sleep(5000);
}
}