说明
在上篇博文中,我使用了guava作为spring的本地缓存,来实现在加载数据到本地的需求。在这个篇博文中,我将记录总结使用caffeine作为本地缓存。在spring5后,spring官方放弃了guava,而使用了性能更优秀的caffeine,本篇将结合springboot2.x来实现caffeine的使用。了解有关caffeine的详细内容请见caffeine。
正文
1.CacheProperties
同样,本篇也采用的是手动配置参数类,没有使用springboot的自动配置。首先是创建配置属性类CacheProperties。
@ConfigurationProperties(prefix = "spring.cache")
public class CacheProperties {
private int initialCapacity; //初始缓存空间大小
private long maximnumSize; //缓存的最大条数
private long maximunmWeight; //缓存的最大权重
private long expireAfterAccess; //最后一次写入或访问后经过固定的时间过期
private long expireAfterWrite; //最后一次写入后经过固定的时间过期
private long refreshAfterWrite; //写入后经过固定的时间刷新缓存
private boolean weakKeys; // key为弱引用
private boolean weakValues; // value为弱引用
private boolean softValues; //value 为软引用
private boolean recordStats; //统计功能
....//省略getter setter方法
}
2.自定义CacheLoader
创建自定义CacheLoader类,在配置cache或CacheManager时如果配置了refreshAfterWrite属性,就必须指定一个CacheLoader。
public class CacheLoadCustom implements CacheLoader{
@Override
public Object load(Object o) throws Exception {
if (o.toString().equalsIgnoreCase("hello")) {
Thread.sleep(3000);
return o.toString();
} else if (o.toString().equalsIgnoreCase("world")) {
Thread.sleep(5000);
return o.toString();
}
return o.toString();
}
@Override
public Object reload(Object key, Object oldValue) throws Exception {
if (key.toString().equalsIgnoreCase("hello")) {
return "world";
} else if (key.toString().equalsIgnoreCase("world")) {
return "hello";
}
return "no value";
}
}
3.配置Cache
创建配置类CacheConfig类,在配置CacheManager类,指定Caffeine对象。关于CacheLoader的指定,可以在创建Caffeine时指定,也可以在配置CacheManager时指定。当缓存不存在时,会根据CacheLoader的load方法进行加载,所以自定义CacheLoader的参数和返回值都是Object。
@EnableConfigurationProperties(CacheProperties.class)
@Configuration
public class CacheConfig {
@Autowired
private CacheProperties cacheProperties;
@Bean("cacheLoader")
public CacheLoadCustom cacheLoadCustom(){
return new CacheLoadCustom();
}
@Bean("cacheCaffeine")
public Caffeine caffeine(){
Caffeine caffeine = Caffeine.newBuilder().maximumSize(cacheProperties.getMaximnumSize());
caffeine.initialCapacity(cacheProperties.getInitialCapacity());
caffeine.refreshAfterWrite(cacheProperties.getRefreshAfterWrite(), TimeUnit.SECONDS);
caffeine.expireAfterWrite(cacheProperties.getExpireAfterWrite(), TimeUnit.SECONDS);
return caffeine;
}
@Bean
public CacheManager cacheManager(@Qualifier("cacheLoader") CacheLoadCustom cacheLoadCustom,
@Qualifier("cacheCaffeine") Caffeine caffeine){
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
caffeineCacheManager.setCacheLoader(cacheLoadCustom);
caffeineCacheManager.setCaffeine(caffeine);
return caffeineCacheManager;
}
}
4.测试
@RestController
public class HelloAction {
@Autowired
private CacheManager cacheManager;
@RequestMapping("/hello")
public String hello(){
long start = System.currentTimeMillis();
String res = cacheManager.getCache("hello").get("hello").get().toString();
long end = System.currentTimeMillis();
return res + " wait time " + (end - start);
}
@RequestMapping("/world")
public String world(){
long start = System.currentTimeMillis();
String res = cacheManager.getCache("world").get("world").get().toString();
long end = System.currentTimeMillis();
return res + " wait time " + (end - start);
}
}
这里,我只简单的配置使用了caffeine,仅实现了通过cacheloader进行缓存的加载和过期缓存的更新。关于caffeine的其他特性,如驱逐策略,异步加载等没有体现。
参考资料:
https://www.jianshu.com/p/c72fb0c787fc
https://blog.csdn.net/xiaolyuh123/article/details/78794012
源码地址:
https://github.com/Edenwds/springboot_study/tree/master/caffeine