SpringBoot&Caffeine 灵活支持多个缓存配置策略
2021-05-03 13:29
标签:不可 ber 允许 引入 oop codis long configure 很多 缓存是几乎所有应用程序性能的关键。很多时候需要分布式缓存(比如常用的 Redis、Codis),但在许多情况下,本地缓存也可以很好地工作,并且不需要分布式缓存的开销和复杂性。 对于 DotNet 开发来说,本地 cache 很方便使用(比如 RuntimeCache 等); 对于 Java 说,也有很多优秀的本地 cache 库(比如 Ehcache、GuavaCache 等),而 Java 这个帝国中,spring 是一个伟大且垄断的存在。针对不同的缓存技术,Spring 定义了如下的 cacheManger 实现。 因此,在许多应用程序中(包括普通的 Spring 和 Spring Boot),你都可以引入相应的依赖包后,简单的把 Tips:spring cache 使用基于动态生成子类的代理机制来对方法的调用进行切面,如果缓存的方法是内部调用而不是外部引用,会导致代理失败,切面失效。 虽然 Spring 有一些默认的缓存管理器实现,有时候,一些外部库总是比简单的实现更好、更灵活。例如,其中一个高性能的 Java 缓存库 Caffeine 。 今天,我们主要目标就是:认识 Caffeine 以及如何实现多缓存灵活配置。 Caffeine 是使用 Java8 对 Guava 缓存的重写版本,缓存类似于 ConcurrentMap,但并不完全相同,可提供接近最佳的命中率。它基于 LRU 算法实现,支持多种缓存过期策略。在 Spring Boot 2.0 中将取代 GuavaCache。 特性如下: 注意: 简单了解了 caffeine 是什么,有哪些属性可用,那么我们回过头来,你会发现,其实 SpringBoot 内部已经提供了一个默认实现 因此,理想情况下,这就是你所需要的一切了:只需简单的创建一个 CacheManager 的 bean,就可以为带 到此,我们大概了解了 caffeine 是个什么,以及应该如何用,那么接下来,我们就用示例说话。看不到代码瞎 BB 也是很让人讨厌的,不是么。 举例如下: 使用起来也很简单,毕竟 springBoot 这么牛 x 的框架提供了很好的集成和灵活性。 通过指定 然鹅~~ 冷静下,真的“灵活”么? 假如一个项目中有很多要缓存(而且也肯定很常见),并且缓存的策略规则也不尽相同时(比如重要的到期时间、初始容量、最大大小等),你是不是就觉得写很多类似的 笔者也翻阅了网上一些文章,但大多是告诉你如何使用自定义规范定义自定义缓存。但是,没有一个实现了我希望的理想状态。 我期望的是:既可以使用默认的一些策略规范自动创建缓存,又可以灵活的自定义设置你想要的缓存策略。 是不是听起来有点贪心?其实,我个人觉得这是追求完美的人很正常的一个想法。 毕竟方法总比困那多~ 那么,接下来,我们就要把这个想法落地。 更多实现细节,请通过移步公众号~ SpringBoot&Caffeine 灵活支持多个缓存配置策略 标签:不可 ber 允许 引入 oop codis long configure 很多 原文地址:https://www.cnblogs.com/hager/p/13197673.html前言
CacheManger
描述
SimpleCacheManager
使用简单的 Collection 来存储缓存,主要用于测试
ConcurrentMapCacheManager
使用 ConcurrentMap 作为缓存技术(默认),需要显式的删除缓存,无过期机制
NoOpCacheManager
仅测试用途,不会实际存储缓存
EhCacheCacheManager
使用 EhCache 作为缓存技术,以前在 hibernate 的时候经常用
GuavaCacheManager
使用 google guava 的 GuavaCache 作为缓存技术(1.5 版本已不建议使用)
CaffeineCacheManager
是使用 Java8 对 Guava 缓存的重写,spring5(springboot2)开始用 Caffeine 取代 guava
HazelcastCacheManager
使用 Hazelcast 作为缓存技术
JCacheCacheManager
使用 JCache 标准的实现作为缓存技术,如 Apache Commons JCS
RedisCacheManager
使用 Redis 作为缓存技术
@Cacheable
打在任何方法上使用它,以使其结果被缓存,以便下次调用该方法时,将返回缓存的结果。
那么,简单认识一下 Caffeine
Caffeine 的一些参数,我们后续也会用到
参数
描述
initialCapacity=[integer]
初始的缓存空间大小(比较常用)
maximumSize=[long]
缓存的最大条数 (比较常用)
maximumWeight=[long]
缓存的最大权重
expireAfterAccess=[duration]
最后一次写入或访问后经过固定时间过期 (比较常用)
expireAfterWrite=[duration]
最后一次写入后经过固定时间过期(比较常用)
refreshAfterWrite=[duration]
创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存 refreshAfterWrite requires a LoadingCache
weakKeys
打开 key 的弱引用
weakValues
打开 value 的弱引用
softValues
打开 value 的软引用
recordStats
开发统计功能
refreshAfterWrite
必须实现 LoadingCache,跟 expire 的区别是,指定时间过后 expire 是 remove 该 key,下次访问是同步去获取返回新值,而 refresh 则是指定时间后,不会 remove 该 key,下次访问会触发刷新,新值没有回来时返回旧值。expireAfterWrite
和 expireAfterAccess
同时存在时,以 expireAfterWrite
为准。maximumSize
和 maximumWeight
不可以同时使用。weakValues
和 softValues
不可以同时使用。CaffeineCacheManager
(具体可以参见源码 org.springframework.cache.caffeine.CaffeineCacheManager
)。这里不再过多的展开,可以自行阅读一下源码了解下~@Cacheable
注释的方法进行缓存。实战
阶段一目标:定义两个 manager,实现不同的缓存配置。
@Configuration
public class CaffeineConfig extends CachingConfigurerSupport {
@Override
@Bean(name = "cacheManager")
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
// 方案一(常用):定制化缓存Cache
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.initialCapacity(100)
.maximumSize(10_000));
return cacheManager;
}
/**
* 在@cacheable使用时,指定cacheManager=specCacheManager
*
* @return CacheManager
*/
@Bean(name = "specCacheManager")
public CacheManager cacheManagerWithSpec() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
// 不允许空值
cacheManager.setAllowNullValues(false);
// 传入一个CaffeineSpec定制缓存,它的好处是可以把配置方便写在配置文件里
cacheManager.setCaffeineSpec(CaffeineSpec.parse("initialCapacity=20,maximumSize=100,expireAfterWrite=10m"));
// 指定使用该策略的CacheNames
cacheManager.setCacheNames(new ArrayList
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Override
@Cacheable(cacheNames = "userSelectOrDefault", cacheManager = "cacheManager", key = "#userId")
public MyUser selectOrDefault(Integer userId) {
System.out.println("我要执行【selectOrDefault】方法的查询逻辑啦~ userId=" + userId);
System.out.println("当前时间:" + LocalDateTime.now().toString());
return new MyUser()
.setUserId(userId)
.setGender(userId % 2)
.setUserName("userName_" + userId);
}
@Override
@Cacheable(cacheNames = "fetchByName", cacheManager = "specCacheManager", key = "#userName")
public MyUser fetchByName(String userName) {
System.out.println("我要执行【fetchByName】方法的查询逻辑啦~userName=" + userName);
System.out.println("当前时间:" + LocalDateTime.now().toString());
int hashCode = userName.hashCode();
return new MyUser()
.setUserId(hashCode)
.setGender(hashCode % 2)
.setUserName(userName);
}
}
@Cacheable
的 cacheNames
、 cacheManager
就可以“灵活”的使用不同的缓存策略了。可能你觉得已经有点小满足了,毕竟能灵活配置了嘛~~cacheManger
有点不爽?阶段二:目标:实现一个既可以手动配置,又可以默认的
CacheManger
下一篇:【算法】折半查找的相关问题
文章标题:SpringBoot&Caffeine 灵活支持多个缓存配置策略
文章链接:http://soscw.com/index.php/essay/81823.html