我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Spring内存缓存Caffeine的基本使用教程分享

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Spring内存缓存Caffeine的基本使用教程分享

项目配置

依赖

首先搭建一个标准的SpringBoot项目工程,相关版本以及依赖如下

本项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发

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

使用实例

引入上面的jar包之后,就可以进入caffeine的使用环节了;我们主要依照官方wiki来进行演练

Home zh CN · ben-manes/caffeine Wiki

caffeine提供了四种缓存策略,主要是基于手动添加/自动添加,同步/异步来进行区分

其基本使用姿势于Guava差不多

1.手动加载

private LoadingCache<String, Integer> autoCache;
private AtomicInteger idGen;
public CacheService() {
      // 手动缓存加载方式
      idGen = new AtomicInteger(100);
      uidCache = Caffeine.newBuilder()
              // 设置写入后五分钟失效
              .expireAfterWrite(5, TimeUnit.MINUTES)
              // 设置最多的缓存数量
              .maximumSize(100)
              .build();
}

1.1 三种失效策略

注意参数设置,我们先看一下失效策略,共有下面几种

权重:

  • maximumSize: 基于容量策略,当缓存内元素个数超过时,通过基于就近度和频率的算法来驱逐掉不会再被使用到的元素
  • maximumWeight: 基于权重的容量策略,主要应用于缓存中的元素存在不同的权重场景

时间:

  • expireAfterAccess: 基于访问时间
  • expireAfterWrite: 基于写入时间
  • expireAfter: 可以根据读更新写入来调整有效期

引用:

  • weakKeys: 保存的key为弱引用
  • weakValues: 保存的value会使用弱引用
  • softValues: 保存的value使用软引用

弱引用:这允许在GC的过程中,当没有被任何强引用指向的时候去将缓存元素回收

软引用:在GC过程中被软引用的对象将会被通过LRU算法回收

1.2 缓存增删查姿势

接下来我们看一下手动方式的使用

public void getUid(String session) {
    // 重新再取一次,这次应该就不是重新初始化了
    Integer uid = uidCache.getIfPresent(session);
    System.out.println("查看缓存! 当没有的时候返回的是 uid: " + uid);

    // 第二个参数表示当不存在时,初始化一个,并写入缓存中
    uid = uidCache.get(session, (key) -> 10);
    System.out.println("初始化一个之后,返回的是: " + uid);

    // 移除缓存
    uidCache.invalidate(session);

    // 手动添加一个缓存
    uidCache.put(session + "_2", 11);

    // 查看所有的额缓存
    Map map = uidCache.asMap();
    System.out.println("total: " + map);

    // 干掉所有的缓存
    uidCache.invalidateAll();
}

查询缓存&添加缓存

  • getIfPresent(key): 不存在时,返回null
  • get(key, (key) -> {value初始化策略}): 不存在时,会根据第二个lambda表达式来写入数据,这个就表示的是手动加载缓存
  • asMap: 获取缓存所有数据

添加缓存

  • put(key, val): 主动添加缓存

清空缓存

  • invalidate: 主动移除缓存
  • invalidateAll: 失效所有缓存

执行完毕之后,输出日志:

查看缓存! 当没有的时候返回的是 uid: null
初始化一个之后,返回的是: 10
total: {02228476-bcd9-412d-b437-bf0092c4a5f6_2=11}

2.自动加载

在创建的时候,就指定缓存未命中时的加载规则

// 在创建时,自动指定加载规则
private LoadingCache<String, Integer> autoCache;
private AtomicInteger idGen;

public CacheService() {
    // 手动缓存加载方式
    idGen = new AtomicInteger(100);
    autoCache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .maximumSize(100)
            .build(new CacheLoader<String, Integer>() {
                @Override
                public @Nullable Integer load(@NonNull String key) throws Exception {
                    return idGen.getAndAdd(1);
                }
            });
}

它的配置,与前面介绍的一致;主要的区别点在于build时,确定缓存值的获取方式

2.1 缓存使用姿势

public void autoGetUid(String session) {
    Integer uid = autoCache.getIfPresent(session);
    System.out.println("自动加载,没有时返回: " + uid);

    uid = autoCache.get(session);
    System.out.println("自动加载,没有时自动加载一个: " + uid);

    // 批量查询
    List<String> keys = Arrays.asList(session, session + "_1");
    Map<String, Integer> map = autoCache.getAll(keys);
    System.out.println("批量获取,一个存在一个不存在时:" + map);

    // 手动加一个
    autoCache.put(session + "_2", 11);
    Map total = autoCache.asMap();
    System.out.println("total: " + total);
}

与前面的区别在于获取缓存值的方式

  • get(key): 不用传第二个参数,直接传key获取对应的缓存值,如果没有自动加载数据
  • getAll(keys): 可以批量获取数据,若某个key不再缓存中,会自动加载;在里面的则直接使用缓存的

实际输出结果如下

自动加载,没有时返回: null
自动加载,没有时自动加载一个: 100
批量获取,一个存在一个不存在时:{02228476-bcd9-412d-b437-bf0092c4a5f6=100, 02228476-bcd9-412d-b437-bf0092c4a5f6_1=101}
total: {02228476-bcd9-412d-b437-bf0092c4a5f6_2=11, 02228476-bcd9-412d-b437-bf0092c4a5f6_1=101, 02228476-bcd9-412d-b437-bf0092c4a5f6=100}

3.异步手动加载

异步,主要是值在获取换粗内容时,采用的异步策略;使用与前面没有什么太大差别

// 手动异步加载缓存
private AsyncCache<String, Integer> asyncUidCache;

public CacheService() {
    asyncUidCache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .maximumSize(100)
            .buildAsync();
}

3.1 缓存使用姿势

public void asyncGetUid(String session) throws ExecutionException, InterruptedException {
    // 重新再取一次,这次应该就不是重新初始化了
    CompletableFuture<Integer> uid = asyncUidCache.getIfPresent(session);
    System.out.println("查看缓存! 当没有的时候返回的是 uid: " + (uid == null ? "null" : uid.get()));

    // 第二个参数表示当不存在时,初始化一个,并写入缓存中
    uid = asyncUidCache.get(session, (key) -> 10);
    System.out.println("初始化一个之后,返回的是: " + uid.get());

    // 手动塞入一个缓存
    asyncUidCache.put(session + "_2", CompletableFuture.supplyAsync(() -> 12));

    // 移除缓存
    asyncUidCache.synchronous().invalidate(session);
    // 查看所有的额缓存
    System.out.println("print total cache:");
    for (Map.Entry<String, CompletableFuture<Integer>> sub : asyncUidCache.asMap().entrySet()) {
        System.out.println(sub.getKey() + "==>" + sub.getValue().get());
    }
    System.out.println("total over");
}
  • getIfPresent: 存在时返回CompletableFuture,不存在时返回null,因此注意npe的问题
  • get(key, Function<>): 第二个参数表示加载数据的逻辑
  • put(key, CompletableFuture<>): 手动加入缓存,注意这里也不是直接加一个具体的value到缓存
  • synchronous().invalidate() : 同步清除缓存
  • getAll: 一次获取多个缓存,同样的是在缓存的取缓存,不在的根据第二个传参进行加载

与前面相比,使用姿势差不多,唯一注意的是,获取的并不是直接的结果,而是CompletableFuture,上面执行之后的输出如下:

查看缓存! 当没有的时候返回的是 uid: null
初始化一个之后,返回的是: 10
print total cache:
5dd53310-aec7-42a5-957e-f7492719c29d_2==>12
total over

4.异步自动加载

在定义缓存时,就指定了缓存不存在的加载逻辑;与第二个相比区别在于这里是异步加载数据到缓存中

private AtomicInteger idGen;
// 自动异步加载缓存
private AsyncLoadingCache<String, Integer> asyncAutoCache;
public CacheService() {
  idGen = new AtomicInteger(100);
  asyncAutoCache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .maximumSize(100)
            .buildAsync(new CacheLoader<String, Integer>() {
                @Override
                public @Nullable Integer load(@NonNull String key) throws Exception {
                    return idGen.getAndAdd(1);
                }
            });
}

4.1 缓存使用姿势

public void asyncAutoGetUid(String session) {
    try {
        CompletableFuture<Integer> uid = asyncAutoCache.getIfPresent(session);
        System.out.println("自动加载,没有时返回: " + (uid == null ? "null" : uid.get()));

        uid = asyncAutoCache.get(session);
        System.out.println("自动加载,没有时自动加载一个: " + uid.get());

        // 批量查询
        List<String> keys = Arrays.asList(session, session + "_1");
        CompletableFuture<Map<String, Integer>> map = asyncAutoCache.getAll(keys);
        System.out.println("批量获取,一个存在一个不存在时:" + map.get());
        
        // 手动加一个
        asyncAutoCache.put(session + "_2", CompletableFuture.supplyAsync(() -> 11));
        
        // 查看所有的额缓存
        System.out.println("print total cache:");
        for (Map.Entry<String, CompletableFuture<Integer>> sub : asyncAutoCache.asMap().entrySet()) {
            System.out.println(sub.getKey() + "==>" + sub.getValue().get());
        }
        System.out.println("total over");

        // 清空所有缓存
        asyncAutoCache.synchronous().invalidateAll();
      } catch (Exception e) {
        e.printStackTrace();
    }
}

输出:

自动加载,没有时返回: null
自动加载,没有时自动加载一个: 102
批量获取,一个存在一个不存在时:{5dd53310-aec7-42a5-957e-f7492719c29d=102, 5dd53310-aec7-42a5-957e-f7492719c29d_1=103}
print total cache:
5dd53310-aec7-42a5-957e-f7492719c29d_2==>11
5dd53310-aec7-42a5-957e-f7492719c29d_1==>103
5dd53310-aec7-42a5-957e-f7492719c29d==>102
total over

以上就是Spring内存缓存Caffeine的基本使用教程分享的详细内容,更多关于Spring内存缓存Caffeine的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Spring内存缓存Caffeine的基本使用教程分享

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Spring内存缓存Caffeine的基本使用教程分享

Caffeine作为当下本地缓存的王者被大量的应用再实际的项目中,可以有效的提高服务吞吐率、qps,降低rt,本文就来简单介绍下Caffeine的使用姿势吧
2023-03-24

Java集合Stream流操作的基本使用教程分享

流操作并不会影响原来的集合,可以简单认为,流操作是把集合中的一个元素逐个复制放到一个首尾相接的流动的水槽中。这篇文章整理了Stream流操作的基本使用,需要的可以参考一下
2023-02-21

【Java基础教程】(七)面向对象篇 · 第一讲:上干货!面向对象的特性、类与对象、内存结构引用分析、垃圾收集器 GC处理、封装性详解、构造方法、匿名对象、简单 Java 类~

Java基础教程之面向对象 · 第一讲 🍉 篇章介绍本节学习目标1️⃣ 面向对象的三个特性2️⃣ 类与对象2.1 基本概念2.2 定义 3️⃣ 引用分析🔍 关于`垃圾收集器 GC`处理的介绍
2023-08-19

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录