1.前言
在整合guava实现限流中我们使用guava--ratelimiter实现了单机限流,本篇我们整合guava实现本地缓存.
2.整个guava cache实现本地缓存
2.1 引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- guava-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
2.2 定义cacheManager
@Configuration
@EnableCaching
@ConfigurationProperties(prefix = "guava.cache.config")
@Data
public class GuavaCacheConfig {
private int concurrencyLevel;
private long maximumSize;
private long expireAfterWrite;
private long refreshAfterWrite;
private int initialCapacity;
@Bean
public CacheManager cacheManager() {
System.out.println(concurrencyLevel);
System.out.println(maximumSize);
System.out.println(expireAfterWrite);
System.out.println(refreshAfterWrite);
System.out.println(initialCapacity);
GuavaCacheManager cacheManager = new GuavaCacheManager();
cacheManager.setCacheBuilder(
CacheBuilder.newBuilder()
//设置并发级别为8 并发级别是指可以同事写缓存的线程数
.concurrencyLevel(concurrencyLevel)
//设置写缓存后10s过期
.expireAfterWrite(expireAfterWrite, TimeUnit.MINUTES)
//设置缓存容量的初始容量为10
.initialCapacity(initialCapacity)
//设置缓存最大容量为100,超过100之后会按照LRU最近最少使用算法来移除缓存项
.maximumSize(maximumSize)
//设置要统计缓存的命中率
.recordStats()
//设置缓存移除通知
.removalListener(
new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());
}
}
)
//如果缓存过期,恰好有多个线程读取同一个key的值,那么guava只允许一个线程去加载数据,其余线程阻塞。
// 这虽然可以防止大量请求穿透缓存,但是效率低下。使用refreshAfterWrite可以做到:只阻塞加载数据的线程,其余线程返回旧数据。
//.refreshAfterWrite(refreshAfterWrite, TimeUnit.MINUTES)
);
return cacheManager;
}
}
2.3 增加配置
guava:
cache:
config:
# 并发级别为,并发级别是指可以同事写缓存的线程数
concurrencyLevel: 8
#缓存最大容量,超过之后会按照LRU最近最少使用算法来移除缓存项
maximumSize: 100
#设置写缓存后,多长时间过期 时间单位为毫秒
expireAfterWrite: 10000
#设置缓存容量的初始容量
initialCapacity: 10
#如果缓存过期,恰好有多个线程读取同一个key的值,那么guava只允许一个线程去加载数据,其余线程
#阻塞。
#这虽然可以防止大量请求穿透缓存,但是效率低下。
#使用refreshAfterWrite可以做到:只阻塞加载数据的线程,其余线程返回旧数据。
#时间单位为 毫秒
refreshAfterWrite: 1000
2.4 测试
使用springCache一样.
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
/**
* 模拟保存数据
* @param key
* @return
*/
@GetMapping("/set/{key}")
@CachePut(value = "keyCache",key = "#key")
public String setKey(@PathVariable String key){
System.out.println(key);
//模拟访问数据库
log.info("~~~~~~访问数据库获保存结果");
return key;
}
/**
* 模拟从获取数据
* @param key
* @return
*/
@GetMapping("/get/{key}")
@Cacheable(value = "keyCache",key = "#key")
public String getKey(@PathVariable String key){
//模拟访问数据库
log.info("访问数据库获取结果");
return key;
}
}
首先我们模拟保存数据,并添加到本地缓存.
接着我们获取刚才保存的数据,
可以发现 控制台并未打印出 "访问数据库获取结果" 这说明返回的数据是本地缓存内的,至此接入成功啦.
[总结]:guava cache 简单好用,纯java配置,作为本地缓存还是很好用的.避免了想ecache那样比较繁琐的xml配置.