本地缓存~

news/2025/2/3 12:06:53 标签: 缓存

前言

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: caffeine
    caffeine:
      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.niftyadmin.cn/n/5840783.html

相关文章

STM32单片机学习记录(2.2)

一、STM32 13.1 - PWR简介 1. PWR&#xff08;Power Control&#xff09;电源控制 &#xff08;1&#xff09;PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编程电压监测器和低功耗模式的功能&#xff1b; &#xff08;2&#xff09;可编程电压监测器&#xff08;…

玩转ChatGPT:DeepSeek测评(科研思路梳理)

一、写在前面 DeepSeek-R1出圈了&#xff0c;把OpenAI的o3-mini模型都提前逼上线了&#xff08;还免费使用&#xff09;。 都号称擅长深度推理&#xff0c;那么对于科研牛马的帮助有多大呢&#xff1f; 我连夜试一试。 二、科研思路梳理 有时候我们牛马们做了一堆结果以后&…

torch numpy seed使用方法

1 import numpy as np np.random.seed(500) np.random.rand(5)array([0.69367953, 0.06171699, 0.6666116 , 0.55920894, 0.08511062])import torch torch.manual_seed(500) torch.rand(5)为了能够复现数据&#xff0c;我们可以使用seed 来控制生成的随机数。设置seed数据来设…

java-抽象类注意点

ChinesePerson 类 public class ChinesePerson extends Person{public ChinesePerson(){}public ChinesePerson(String name, int age){super(name, age);}Overridepublic void greet() {System.out.println("你好&#xff0c;我的名字叫" this.getName());} }Engl…

Unity打包安卓报错sdk version 0.0 < 26.0(亲测解决)

问题描述和尝试解决方案&#xff1a; Unity打包安卓报错sdk version 0.0 < 26.0高版本Unity手动指定SDK地址时&#xff0c;比较容易出现上述错误高手支招1&#xff1a;修改sdk的tools文件夹中package.xml的obsolete"false"无解&#xff0c;因为打开platform-tool…

react中useEffect的使用

2.useEffect-清楚副作用

使用C#开发一款通用数据库管理工具

由于经常使用各种数据库&#xff0c;笔者自己动手丰衣足食&#xff0c;使用C#开发了一款通用数据库管理工具&#xff0c;支持Mysql、Oracle、Sqlite、SQL Server等数据库的表、视图、存储过程、函数管理功能&#xff0c;并支持导入导出、数据字典生成、拖拽式跨机器跨库数据一键…

LeetCode:121.买卖股票的最佳时机1

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;121.买卖股票的最佳时机1 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票…