本地缓存~

news/2025/2/3 23:02:37/

前言

Caffeine是使用Java8对Guava缓存的重写版本,在Spring Boot 2.0中取而代之,基于LRU算法实现,支持多种缓存过期策略。

以下摘抄于https://github.com/ben-manes/caffeine/wiki/Benchmarks-zh-CN

基准测试通过使用Java microbenchmark harness 来提供准确的分析结果。这些缓存将被如下配置,

  • Caffeine 和 ConcurrentLinkedHashMap根据CPU的数量调整其内部大小。
  • Guava 并发度被配置为 64 (默认情况下为 4 来减少内存开销)。请注意Guava将会#2063 解决性能问题,但已经被积压多年(提升25倍以上!)。
  • Ehcache v2 内部被硬编码为100段, 而 v3 版本没有进行分段
  • Infinispan “old” 是一个类似Guava的缓存,并且并发度被配置为64
  • Infinispan "new"是使用无锁deque(默认版本为 v7.2+)重写的

本地缓存对比

特性GuavaCaffeine
自动加载实体到缓存✔️✔️
自动刷新✔️✔️
过期或被删除的机制✔️✔️
自动回收✔️✔️
统计累计访问缓存✔️✔️
异步✔️
写入外界资源✔️
算法S-LRU 分段的最近最少未使用算法W-TinyLFU 高命中率、低内存占用
持久化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用指南

pom引入

<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId>
</dependency>

配置

  • maximumSize:

  • refreshAfterWrite

  • expireAfterWrite

  • expireAfterAccess

  • maximumWeight

preview

方法

  • Get

    如果Guava 的load()返回时null,那么get()会抛出异常ExecutionException,而Caffeine就不会,会返回null

  • getAll

    获取多个key的value,返回一个map

  • load

    刷新

  • getUnchecked(): guava才有,Caffeine没有,所以Caffeine需要做好控判断

  • Caffeine.newBuilder().build()创建LoadingCache

  • invalidate

  • cleanUp

缓存填充方法

  • 手动填充

    # 0. 构建LoadingCache
    Cache<String, DataObject> cache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).maximumSize(280).build();String key = "test";
    # 1. 缓存中不存指定的值,则方法将返回 null
    DataObject dataObject = cache.getIfPresent(key); cache.put(key, "20220510 Demo演示");
    # 2. return "20220510 Demo演示"
    dataObject = cache.getIfPresent(key);# 3. 如果key的值不存在,则返回“空时mock一个值”
    dataObject = cache.get(key, k -> "空时mock一个值"); # 4. 手动失效
    cache.invalidate(key);
    # 返回null
    dataObject = cache.getIfPresent(key);
    
  • 同步加载

    LoadingCache<String, DataObject> cache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.MINUTES).build(k -> "Data for " + k);
    
  • 异步加载

    AsyncLoadingCache<String, DataObject> cache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.MINUTES).buildAsync(k -> "Data for " + k);String key = "test-async";cache.get(key).thenAccept(dataObject -> {assertNotNull(dataObject);assertEquals("Data for " + key, dataObject.getData());
    });cache.getAll(Arrays.asList("test-async", "test-async2", "test-async3")).thenAccept(dataObjectMap -> assertEquals(3, 3));
    

注解的实现方式

Springboot 配置

spring:
# 配置缓存,初始缓存容量为10,最大容量为200,过期时间(这里配置写入后过期时间为3秒)cache:type: caffeinecaffeine:spec: initialCapacity=10,maximumSize=200,expireAfterWrite=3s

@Cacheable

 // key 是指传入时的参数@Cacheable(value="users", key="#id")public Integer find(Integer id) {return id;}
// 表示第一个参数
@Cacheable(value="users", key="#p0")public Long find(Long id) {return id;}
// 表示User中的id值@Cacheable(value="users", key="#user.id")public User find(User user) {return user;}// 表示第一个参数里的id属性值@Cacheable(value="users", key="#p0.id")public User find(User user) {return user;}// 表示第一个参数里的id属性值@Cacheable(value="users", key="#root.getXXX(#user.id)")public User find(User user) {return user;}public String getXXX(String id){// 获取上文问的traceid 方法// ...return 上下文的traceId;
}// 根据条件判断是否缓存@Cacheable(value="users", key="#user.id", condition="#user.id%2==0"/*,unless="#result==null"*/)public User find(User user) {return user;}

注意事项

  • SpringBoot启动类开启@EnableCaching

  • A class 调用 B class 的@Cacheable的方法,一定是public方法

  • A class 调用 B class 的@Cacheable的方法,B 一定是@Component、@Service等

  • B class 的@Cacheable的方法xx1调用@Cacheable的方法xx2,B缓存不起作用。解决方案:Spring上下文手动获取Bean实例调用xx2,或者AopContext.currentProxy())调用xx2,不过ApoContenxt这个,需要在启动累开启@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

  • 开启@EnableCache,注意区分Redis的CacheManager,在注解通过指定@Cacheable(cacheManager=“caffeineCacheManager”,…)


http://www.ppmy.cn/news/1569075.html

相关文章

2025年01月31日Github流行趋势

项目名称&#xff1a;Qwen2.5项目地址url&#xff1a;https://github.com/QwenLM/Qwen2.5项目语言&#xff1a;Shell历史star数&#xff1a;13199今日star数&#xff1a;459项目维护者&#xff1a;jklj077, JustinLin610, bug-orz, huybery, JianxinMa项目简介&#xff1a;Qwen…

Nginx前端后端共用一个域名如何配置

在 Nginx 中配置前端和后端共用一个域名的情况&#xff0c;通常是通过路径或子路径将请求转发到不同的服务。以下是一个示例配置&#xff0c;假设&#xff1a; 前端静态文件在 /var/www/frontend/。 后端 API 服务运行在 http://127.0.0.1:5000。 域名是 example.com&#xff…

Mono里运行C#脚本39—mono_jit_runtime_invoke函数

当脚本MonoEmbed里的Main ()函数JIT编译完成之后,那么就需要在C代码里运行受托管的代码,即是C#的代码。要运行托管的代码,这是需要初始化一个运行环境,以便把参数从C代码传送给托管代码,又需要从托管代码返回值传送回到C代码。 在这里是通过函数mono_jit_runtime_invoke来…

SSRF 漏洞利用 Redis 实战全解析:原理、攻击与防范

目录 前言 SSRF 漏洞深度剖析 Redis&#xff1a;强大的内存数据库 Redis 产生漏洞的原因 SSRF 漏洞利用 Redis 实战步骤 准备环境 下载安装 Redis 配置漏洞环境 启动 Redis 攻击机远程连接 Redis 利用 Redis 写 Webshell 防范措施 前言 在网络安全领域&#xff0…

【数据结构】(3)包装类和泛型

一、包装类 1、什么是包装类 将基础类型包装成的类就是包装类。由于基础类型不是继承 Object 类的类&#xff0c;所以在泛型不能直接支持基础类型&#xff0c;为了解决这个问题&#xff0c;就需要把基础类型转换为对应的包装类。 基础类型对应的包装类 基础类型包装类byteByte…

全程Kali linux---CTFshow misc入门(25-37)

第二十五题&#xff1a; 提示&#xff1a;flag在图片下面。 直接检查CRC&#xff0c;检测到错误&#xff0c;就直接暴力破解。 暴力破解CRC的python代码。 import binascii import struct def brute_force_ihdr_crc(filename): # 读取文件二进制数据 with open(filen…

城市道路车辆自行车摩托车公交车检测数据集VOC+YOLO格式5236张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;5236 标注数量(xml文件个数)&#xff1a;5236 标注数量(txt文件个数)&#xff1a;5236 …

在K8S中,pending状态一般由什么原因导致的?

在Kubernetes中&#xff0c;资源或Pod处于Pending状态可能有多种原因引起。以下是一些常见的原因和详细解释&#xff1a; 资源不足 概述&#xff1a;当集群中的资源不足以满足Pod或服务的需求时&#xff0c;它们可能会被至于Pending状态。这通常涉及到CPU、内存、存储或其他资…