Caffeine cache实现本地缓存(简单又清楚)
Caffeine cache实现本地缓存题
- 缓存填充策略
- 手动加载
- 介绍:
- 使用方式:
- 同步加载
- 介绍:
- 使用方式:
- 异步加载
- 介绍:
- 注意: 异步和同步使用方式相似, 这里的话主要写一下创建和异步转同步
- 使用方式:
- 过期策略
- 基于大小过期
- 介绍:当缓存超出后,使用W-TinyLFU算法进行缓存淘汰处理
- 使用方式:
- 基于权重过期
- 介绍:
- 使用方式:
- 基于时间过期
- 介绍:
- 使用方式:
- 基于引用回收
- 介绍:
- 使用方式:
- 基本使用
- 手动删除
- 使用方式:
- 自动刷新
- 使用方式:
- 移除通知
- 使用方式:
- 外部存储
- 使用方式:
- 统计缓存使用情况
- 使用方式:
- 实例整合
- 编码方式
- 使用方式:
- 注解方式(整合SpringBoot的cache)
- 介绍:
- 使用方式:
- @Cacheable注解:
- @CachePut注解:
- @CacheEvict注解:
- @CacheConfig注解:
- @Caching注解:
- 简易缓存工具类
缓存填充策略
介绍:缓存的填充方式有三种,手动、同步和异步
手动加载
介绍:
手动控制缓存的增删改处理,主动增加、获取以及依据函数式更新缓存,底层使用ConcurrentHashMap进行节点存储,因此get方法是安全的。批量查找可以使getAllPresent()方法或者带填充默认值的getAll()方法
使用方式:
@Test
void test1() {com.github.benmanes.caffeine.cache.@NonNull Cache<String, String> cache = Caffeine.newBuilder()// 最大数量.maximumSize(100)// 设置缓存策略在1天未写入过期缓存.expireAfterAccess(1, TimeUnit.DAYS).build();// 存入缓存cache.put("cl", "cl");// 根据键值获取缓存System.out.println(cache.getIfPresent("cl"));// 根据键值获取缓存, 如果为空则调用后面的参是System.out.println(cache.get("abc", this::buildLoader));// 根据键值清除缓存cache.invalidate("abc");System.out.println(cache.getIfPresent("abc"));
}
// 缓存后面执行的方法String buildLoader(String k) {return k + "+default";
}
同步加载
介绍:
LoadingCache对象进行缓存的操作,使用CacheLoader进行缓存存储管理。 批量查找可以使用getAll()方法。 默认情况下, getAll()将会对缓存中没有值的key分别调用CacheLoader.load方法来构建缓存的值(build中的表达式)。我们可以重写CacheLoader.loadAll方法来提高getAll()的效率。
使用方式:
@Test
void test1() {LoadingCache<String, String> loadingCache = Caffeine.newBuilder().maximumSize(100).expireAfterAccess(1, TimeUnit.DAYS)// getAll将会对缓存中, 没有值的key分别调用CacheLoader.load方法来构建缓存的值.build(this :: buildLoader);// 存储要添加的缓存List<String> keys = new ArrayList<>();keys.add("cl");keys.add("b");keys.add("c");keys.add("d");// 返回一个mapMap<String, String> cacheAll = loadingCache.getAll(keys);System.out.println(cacheAll.get("b"));System.out.println(cacheAll.get("c"));System.out.println(cacheAll.get("a"));
}
// 缓存后面执行的方法String buildLoader(String k) {return k + "+default";
}
异步加载
介绍:
AsyncLoadingCache对象进行缓存管理,get()返回一个CompletableFuture对象,默认使用ForkJoinPool.commonPool()来执行异步线程,但是我们可以通过Caffeine.executor(Executor) 方法来替换线程池
注意: 异步和同步使用方式相似, 这里的话主要写一下创建和异步转同步
使用方式:
@Test
void test1() {AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder().maximumSize(100).expireAfterAccess(1,TimeUnit.DAYS).buildAsync(k-> this.buildLoaderAsync(k).get());try {System.out.println(asyncLoadingCache.get("123").get());} catch (Exception e) {e.printStackTrace();}
}
// 类似同步的load
CompletableFuture<String> buildLoaderAsync(String k) {return CompletableFuture.supplyAsync(() -> k + "buildLoaderAsync");
}
转换使用方式:
AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder().maximumSize(100).expireAfterAccess(1,TimeUnit.DAYS).buildAsync(k -> this.buildLoaderAsync(k).get());
// 异步转同步
LoadingCache<String, String> cache = asyncLoadingCache.synchronous();
System.out.println("------------");
System.out.println(cache.get("dd"));
过期策略
介绍:
Caffeine的缓存清除是惰性的,可能发生在读请求后或者写请求后
比如说有一条数据过期后,不会立即删除,可能在下一次读/写操作后触发删除(类比于redis的惰性删除)。
如果读请求和写请求比较少,但想要尽快的删掉cache中过期的数据的话,
可以通过增加定时器的方法,定时执行cache.cleanUp()方法(异步方法,可以等待执行),触发缓存清除操作。
基于大小过期
介绍:当缓存超出后,使用W-TinyLFU算法进行缓存淘汰处理
使用方式:
maximumSize()方法,参数是缓存中存储的最大缓存条目,当添加缓存时达到条目阈值后,将进行缓存淘汰操作// 使用方式 AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder().maximumSize(100)
基于权重过期
介绍:
通过权重来计算,每个实体都有不同的权重,总权重到达最高时淘汰实体。
weigher()方法可以指定缓存所占比重,maximumWeight()方法指定最大的权重阈值,当添加缓存超过规定权重后,进行数据淘汰
使用方式:
com.github.benmanes.caffeine.cache.@NonNull LoadingCache<String, String> cache = Caffeine.newBuilder().maximumWeight(10).weigher(new Weigher<Object, Object>() {@Overridepublic @NonNegative int weigh(@NonNull Object o, @NonNull Object o2) {System.out.println("key" + o + "value" + o2);return 5;}}).build(this::buildLoader);
List<String> list = Lists.newArrayList("c1", "c2", "c3");
cache.put(list.get(0), list.get(0));
System.out.println(list.get(0) + "--" + cache.get(list.get(0)));
cache.put(list.get(1), list.get(1));
System.out.println(list.get(1) + "---" + cache.get(list.get(1)));
System.out.println(cache.getAll(list));
基于时间过期
介绍:
expireAfterAccess():缓存访问后,一定时间失效;即最后一次访问或者写入开始时计时。
expireAfterWrite():缓存写入后,一定时间失效;以写入缓存操作为准计时。(在最后一次写入缓存后开始计时,在指定的时间后过期。)
expireAfter():自定义缓存策略,满足多样化的过期时间要求。
这里只展示after, 其他的话 使用方式大致相同,自己动手试试
注意:当expireAfterAccess和expireAfterWrite同时存在时,只有expireAfterWrite有效
使用方式:
com.github.benmanes.caffeine.cache.@NonNull LoadingCache<String, String> cache = Caffeine.newBuilder().expireAfter(new Expiry<Object, Object>() {// 创建后过期@Overridepublic long expireAfterCreate(@NonNull Object o, @NonNull Object o2, long l) {return 1;}// 更新后过期@Overridepublic long expireAfterUpdate(@NonNull Object o, @NonNull Object o2, long l, @NonNegative long l1) {return 1;}// 读取后过期@Overridepublic long expireAfterRead(@NonNull Object o, @NonNull Object o2, long l, @NonNegative long l1) {return 1;}}).build(this::buildLoader);
基于引用回收
介绍:
使用方式:
基本使用
手动删除
使用方式:
自动刷新
使用方式:
refreshAfterWrite:这里设置的是1分钟后自动刷新
移除通知
使用方式:
外部存储
使用方式:
统计缓存使用情况
使用方式:
实例整合
编码方式
使用方式:
1、缓存配置类
@Configuration
public class CacheConfig {@Beanpublic Cache<String, Object> caffeineCache() {return Caffeine.newBuilder()// 设置最后一次写入或访问后经过固定时间过期.expireAfterWrite(60, TimeUnit.SECONDS)// 初始的缓存空间大小.initialCapacity(100)// 缓存的最大条数.maximumSize(1000).build();}
}
2、使用
注意:这里我只写了存入的写法, 如果要获取缓存,用cache的get缓存我们存储的key就可以了。
如:
// 以下代码的具体含义请看文章, 文章都有介绍,如果没有 可以评论 我会给你进行解答
cache.put(1,"测试缓存")
// 获取缓存
cache.get("1");
// 如果你使用get爆红, 那可能是因为你没有填写第二个,那么你可以这样做
cache.get("1", value -> value);
// 或者
cache.asMap().get("1");
示例:
private final Cache<Object, Object> cache;
public FeedbackServiceImpl( Cache<Object, Object> cache) {this.cache = cache;
}
public void insertFeedBack(Feedback feedback) {int i = feedbackMapper.insert(feedback);cache.put(feedback.getId(), feedback);
}
注意:如果你只是简单的使用, 你可以使用末文的缓存工具类
注解方式(整合SpringBoot的cache)
介绍:
使用方式:
@Cacheable注解:
@CachePut注解:
@CacheEvict注解:
@CacheConfig注解:
// 一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用
@CacheConfig(cacheNames="emp") //抽取缓存的公共配置
@Caching注解:
示例:
// 开启缓存
@EnableCaching
public class Springboot01CacheApplication {public static void main(String[] args) {SpringApplication.run(Springboot01CacheApplication.class, args);}
}// 其他方法使用和他一样, 具体可以看代码,来自己动动手试试看@Cacheable(cacheNames = {"emp"},condition = "#id>0")public Employee getEmp(Integer id){System.out.println("查询"+id+"号员工");Employee emp = employeeMapper.getEmpById(id);return emp;}
简易缓存工具类
具体含义看代码注释
/*** @author huangye 所谓致知在格物者,言欲致吾之知,在即物而穷其理也。* @version 1.0 2020/10/4*/
public class CacheUtil{private static Cache<String, Object> cache;static {cache = createCache();}/*** 插入缓存 | 更新缓存* @param cacheName 缓存前缀* @param key 键* @param value 值*/public static void saveCache(String cacheName, String key, Object value) {System.out.printf("存储缓存的数据 key(%s) value(%s)",cacheName + "-" + key, value);System.out.println();cache.asMap().put(cacheName + "-" + key, value);}/*** 根据键获取缓存* @param cacheName 缓存前缀* @param key 键* @return Object类型, 由使用者自己转换*/public static Object getCache(String cacheName, String key) {System.out.printf("获取缓存的数据 key(%s) value(%s)",cacheName + "-" + key,cache.asMap().get(cacheName + "-" + key) );System.out.println();return cache.asMap().get(cacheName + "-" + key);}/*** 根据键值删除缓存* @param cacheName 缓存前缀* @param key 建*/public static void deleteCache(String cacheName, String key) {System.out.printf("删除缓存的数据 key(%s)", cacheName + "-" + key);System.out.println();cache.asMap().remove(cacheName + "-" + key);}private static class CacheSingletonHolder {private final static Cache<String, Object> CACHE = Caffeine.newBuilder()// 初始的缓存空间大小.initialCapacity(100)// 缓存的最大条数.maximumSize(1000)// 最后一次缓存访问过后,7天后失效.expireAfterAccess(7, TimeUnit.DAYS).build();}private static Cache<String, Object> createCache() {return CacheSingletonHolder.CACHE;}
}
ps:这里的图片都来源于我学习时做的笔记(下图位证), 因为有的是在网上找文章学习的,所以可能会遇到有的是和别人一样的内容,我是想着吧那些之前看的文章放到文章末尾的,但是我找不到了非常抱歉, 我这里的话只是想做个知识的汇总,如果有错误的地方,可以评论留言 我会改正,谢谢
Caffeine cache实现本地缓存(简单又清楚)相关推荐
- 干掉 GuavaCache:Caffeine 才是本地缓存的王
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 话说,中间件的选择上,Spring(SpringBoot ...
- ehcache缓存原理_干掉GuavaCache:Caffeine才是本地缓存的王
话说,中间件的选择上,Spring(SpringBoot)一直是业界的风向标.比如Spring一直使用「Jackson」,而没有使用Gson和fastjson.SpringBoot2.0默认数据库连接 ...
- 干掉GuavaCache:Caffeine才是本地缓存的王
点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群",加入新技术 话说,中间件的选择上,Spring(SpringBoot)一直是业 ...
- guava_使用Google Guava Cache进行本地缓存
guava 很多时候,我们将不得不从数据库或另一个Web服务获取数据或从文件系统加载数据. 在涉及网络呼叫的情况下,将存在固有的网络延迟,网络带宽限制. 解决此问题的方法之一是在应用程序本地拥有一个缓 ...
- 使用Google Guava Cache进行本地缓存
很多时候,我们将不得不从数据库或另一个Web服务获取数据或从文件系统加载数据. 在涉及网络呼叫的情况下,将存在固有的网络等待时间,网络带宽限制. 解决此问题的方法之一是在应用程序本地拥有一个缓存. 如 ...
- java 自动过期缓存_Java自动过期本地缓存简单实现
实际项目中常常需要用到本地缓存,特别是一些固定不变的数据,不想频繁调接口,因为http请求本身需要耗时,下面几个类对本地缓存作了简单实现,支持自动过期功能 LocalCache.javainterfa ...
- java guava cache_java使用guava cache实现本地缓存
cache = CacheBuilder.newBuilder() .recordStats() .maximumSize(5000000) .expireAfterWrite(1, TimeUnit ...
- Google Guava Cache高效本地缓存
目录 Guava Cache使用需求和场景 需求 场景 缓存设置 缓存的并发级别 缓存的初始容量设置 设置最大存储 缓存清除策略 基于存活时间的清除策略 基于容量的清除策略 基于权重的清除 策略 显式 ...
- Java高性能本地缓存框架Caffeine
文章目录 Java高性能本地缓存框架Caffeine 如何使用 缓存加载 手动加载 自动加载 手动异步加载 自动异步加载 过期策略 基于大小 基于时间 基于引用 Caffeine.weakKeys() ...
最新文章
- 每个设计师应该阅读的8本书
- 关于iOS去除数组中重复数据的几种方法
- python 内置函数 eval()函数 (用来执行一个字符串表达式,并返回表达式的值)
- 【转】Luajit-2.1.0-beta1的发布和生成arm64用bytecode的解脱
- URAL 1682 Crazy Professor (并查集)
- 临床必备 | 第 5 期全基因组/外显子组家系分析理论和实战
- 改善深层神经网络:超参数调整、正则化以及优化——2.8 Adam算法(Adaptive Moment Estimation)
- 【Ubuntu引导】EFI系统分区.删除不掉,也不能格式化,如何粘力删除 efi 隐藏分区
- 【操作系统/OS笔记17】文件系统基本概念、文件描述符、文件系统访问、文件别名、文件系统种类
- PowerDesigner一些小技巧
- JavaScript 盖尔-沙普利算法
- 【图像压缩】基于matlab GUI DCT图像压缩【含Matlab源码 842期】
- 关于笔记本测试的面试准备 2021-10-11
- 计算机科学与技术的学士服是什么颜色的,学士服颜色分类 各色学士服都有什么讲究...
- 庆祝北大“如何制作MOOC”课程取得优秀成绩
- 错误提示Incompatible file format错误原因和解决方案
- 测试人员,如何对直播类产品的直播质量进行测试呢?
- js做个随机点名的小游戏
- python如何在图片上写字
- Jieyue捷阅网购物商城项目介绍说明
热门文章
- Fragment和Activity两种沉浸式状态栏的实现
- 实战 | 用Python和MediaPipe搭建一个嗜睡检测系统 (详细步骤 + 源码)
- inventor2019有无CAE_autodeskinventor2019-独木成林
- 江汉大学计算机专业男女比,2018全国高校男女比例排行榜出炉!哪所大学最难找对象?...
- 建立在互联网上的公益金字塔
- 黄瓜西红柿为何不能同吃?(图)
- 11万字AI赋能智慧水利模型训练平台建设方案
- 精灵图的使用以及css其他效果运用
- 什么是spring?spring组成模块、spring优缺点、应用场景、bean的生命周期、线程并发问题
- 【SRIO】1、RapidIO协议概述