Springcloud学习笔记68--springboot 整合Caffeine 本地缓存
1 本地缓存介绍
缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。
之前介绍过 Redis 这种 NoSql 作为缓存组件,它能够很好的作为分布式缓存组件提供多个服务间的缓存,但是 Redis 这种还是需要网络开销,增加时耗。本地缓存是直接从本地内存中读取,没有网络开销,例如秒杀系统或者数据量小的缓存等,比远程缓存更合适。
2 缓存组件 Caffeine 介绍
按 Caffeine Github 文档描述,Caffeine 是基于 JAVA 8 的高性能缓存库。并且在 spring5 (springboot 2.x) 后,spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。
3 具体使用案例
3.1 引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.9.3</version> </dependency>
3.2 缓存使用步骤
3.2.0 基础知识
在Cache接口中,定义了get、put、evict、clear等方法,分别对应缓存的存入、取出、删除、清空操作。不过我们这里不直接使用Cache接口,AbstractValueAdaptingCache是一个抽象类,它已经实现了Cache接口,是spring在Cache接口的基础上帮助我们进行了一层封装,所以我们直接继承这个类就可以。
继承AbstractValueAdaptingCache抽象类后,除了创建Cache的构造方法外,还需要实现下面的几个方法:
// 在缓存中实际执行查找的操作,父类的get()方法会调用这个方法 protected abstract Object lookup(Object key); // 通过key获取缓存值,如果没有找到,会调用valueLoader的call()方法 public <T> T get(Object key, Callable<T> valueLoader); // 将数据放入缓存中 public void put(Object key, Object value); // 删除缓存 public void evict(Object key); // 清空缓存中所有数据 public void clear(); // 获取缓存名称,一般在CacheManager创建时指定 String getName(); // 获取实际使用的缓存 Object getNativeCache();
而CaffeineCache就实现了这些方法;
3.2.1 开启基于注解的缓存
第一步:开启基于注解的缓存,使用 @EnableCaching 标注在 springboot 主启动类上
3.2.2 缓存配置类CacheConfig
Caffeine常用配置说明:
initialCapacity=[integer]: 初始的缓存空间大小 maximumSize=[long]: 缓存的最大条数 maximumWeight=[long]: 缓存的最大权重 expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期 expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期 refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存 weakKeys: 打开key的弱引用 weakValues:打开value的弱引用 softValues:打开value的软引用 recordStats:开发统计功能 注意: expireAfterWrite和expireAfterAccess同时存在时,以expireAfterWrite为准。 maximumSize和maximumWeight不可以同时使用 weakValues和softValues不可以同时使用
需要说明的是,使用配置文件的方式来进行缓存项配置,一般情况能满足使用需求,但是灵活性不是很高,如果我们有很多缓存项的情况下写起来会导致配置文件很长。所以一般情况下你也可以选择使用bean的方式来初始化Cache实例。
SimpleCacheManager:
这种缓存管理器允许你在应用程序启动时通过配置多个CaffeineCache来创建多个缓存。
这种方式可以让你为每个方法单独配置缓存过期时间。
CaffeineCacheManager:
这种缓存管理器使用了一个全局的Caffeine配置来创建所有的缓存。
这种方式不能为每个方法单独配置缓存过期时间,但是可以在程序启动时配置全局的缓存配置,这样就可以轻松地设置所有方法的缓存过期时间。
总结:
如果你希望为每个方法单独配置缓存过期时间,那么建议使用第一种方式。
@Configuration @EnableCaching public class CacheConfig { /** * Caffeine配置说明: * initialCapacity=[integer]: 初始的缓存空间大小 * maximumSize=[long]: 缓存的最大条数 * maximumWeight=[long]: 缓存的最大权重 * expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期 * expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期 * refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存 * weakKeys: 打开key的弱引用 * weakValues:打开value的弱引用 * softValues:打开value的软引用 * recordStats:开发统计功能 * 注意: * expireAfterWrite和expireAfterAccess同事存在时,以expireAfterWrite为准。 * maximumSize和maximumWeight不可以同时使用 * weakValues和softValues不可以同时使用 */ @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); List list = new ArrayList<>(); //循环添加枚举类中自定义的缓存,可以自定义 for (CacheEnum cacheEnum : CacheEnum.values()) { list.add(new CaffeineCache(cacheEnum.getName(), Caffeine.newBuilder() .initialCapacity(50) .maximumSize(1000) .expireAfterAccess(cacheEnum.getExpires(), TimeUnit.SECONDS) .build())); } cacheManager.setCaches(list); return cacheManager; } }
3.2.3 标注缓存注解
具体调用缓存。
注:这里使用 @Cacheable 注解就可以将运行结果缓存,以后查询相同的数据,直接从缓存中取,不需要调用方法。
cache方面的注解主要有以下5个:
- @Cacheable 触发缓存入口(这里一般放在创建和获取的方法上,@Cacheable注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存)
- @CacheEvict 触发缓存的eviction(用于删除的方法上)
- @CachePut 更新缓存且不影响方法执行(用于修改的方法上,该注解下的方法始终会被执行)
- @Caching 将多个缓存组合在一个方法上(该注解可以允许一个方法同时设置多个注解)
- @CacheConfig 在类级别设置一些缓存相关的共同配置(与其它缓存配合使用)
说一下@Cacheable 和 @CachePut的区别:
@Cacheable:它的注解的方法是否被执行取决于Cacheable中的条件,方法很多时候都可能不被执行。
@CachePut:这个注解不会影响方法的执行,也就是说无论它配置的条件是什么,方法都会被执行,更多的时候是被用到修改上。
下面介绍一下 @Cacheable 这个注解常用的几个属性:
- cacheNames/value :用来指定缓存组件的名字
- key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)
- keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用
- cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。
- condition :可以用来指定符合条件的情况下才缓存
- unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)
- sync :是否使用异步模式。
① cacheNames
用来指定缓存组件的名字,将方法的返回结果放在哪个缓存中,可以是数组的方式,支持指定多个缓存。
② key
缓存数据时使用的 key。默认使用的是方法参数的值。可以使用 spEL 表达式去编写。
③ keyGenerator
key 的生成器,可以自己指定 key 的生成器,通过这个生成器来生成 key。
这样放入缓存中的 key 的生成规则就按照你自定义的 keyGenerator 来生成。不过需要注意的是:
@Cacheable 的属性,key 和 keyGenerator 使用的时候,一般二选一。
④ condition
符合条件的情况下才缓存。方法返回的数据要不要缓存,可以做一个动态判断。
⑤ unless
否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。
⑥ sync
是否使用异步模式。默认是方法执行完,以同步的方式将方法返回的结果存在缓存中。
参考文献:
https://blog.csdn.net/m0_71777195/article/details/126225712
https://blog.csdn.net/zl1zl2zl3/article/details/110987968 (推荐)
https://blog.csdn.net/zhipengfang/article/details/121868030 (推荐)
https://zhuanlan.zhihu.com/p/109226599
https://m.elecfans.com/article/2329925.html
https://blog.csdn.net/Trunks2009/article/details/123982910
https://blog.csdn.net/u011943534/article/details/129164025
https://www.cnblogs.com/zhangzhixi/p/17029258.html