SpringBoot使用本地缓存——Caffeine

news2024/11/26 15:37:39

SpringBoot使用本地缓存——Caffeine

缓存,想必大家都用过,将常用的数据存储在缓存上能在一定程度上提升数据存取的速度。这正是局部性原理的应用。之前用的缓存大多是分布式的,比如Redis。使用Redis作为缓存虽然是大多数系统的选择,但是需要另起服务,且会增加一定的耗时在数据传输上。对于一些小型应用,用Redis就有点大材小用了,此时便可以使用本地缓存。

本地缓存的技术选型:

  • 使用 ConcurrentHashMap 作为缓存

    这个是最简单的缓存使用,但是没有一定的内存淘汰策略,用作缓存来使用,功能比较单一。需要开发人员进行定制化开发。

  • Guava Cache

    Guava是Google团队开源的一款 Java 核心增强库,包含集合、并发原语、缓存、IO、反射等工具箱,性能和稳定性上都有保障,应用十分广泛,强烈推荐。其中 Guava Cache 支持很多特性,比如:支持最大容量限制、支持两种过期删除策略(插入时间和访问时间)、支持简单的统计功能、基于LRU算法实现

  • 本文将要介绍的Caffeine缓存

    Caffeine是一个高性能的Java本地缓存库,设计用于提供快速响应时间和高并发处理能力。它具有类似于Guava缓存的简单易用的API,同时也提供了许多额外的功能和性能优化。Caffeine支持缓存大小限制、缓存过期策略、异步加载数据等特性,可以帮助开发人员在应用程序中有效地管理和优化缓存。Caffeine还提供了可自定义的缓存策略和监听器,以帮助开发人员根据实际需求定制缓存行为。

  • 基于Ehcache实现本地缓存

    Ehcache是一个流行的Java开源缓存框架,用于在应用程序中管理缓存数据。它被广泛用于提高应用程序性能,减少数据库访问频率,和减少网络开销。同Caffeine和Guava Cache相比,Ehcache的功能更加丰富,扩展性更强。

Caffeine本地缓存

在项目开发中,为提升系统性能,减少 IO 开销,采用本地缓存是必不可少的。最常见的本地缓存是 Guava 和 Caffeine。Caffeine 是基于 Google Guava Cache 设计经验改进的结果,相较于 Guava 在性能和命中率上更具有效率,你可以认为其是 Guava Plus版本。

使用步骤

步骤 1: 添加依赖

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.5</version> <!-- 确保使用最新版本 -->
</dependency>

<!-- Spring Boot Cache 的依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

步骤 2: 配置 Caffeine 缓存管理器

package com.supermap.ai.agent.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

/**
 * @Author: wangrongyi
 * @Date: 2024/7/8 14:02
 * @Description: 缓配配置类
 */
@Configuration
@Slf4j
public class CaffeineConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        //Caffeine配置
        Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
                //最后一次写入后经过固定时间过期
                .expireAfterWrite(600, TimeUnit.SECONDS)
                //maximumSize=[long]: 缓存的最大条数
                .maximumSize(1000);
        cacheManager.setCaffeine(caffeine);
        log.info("缓存配置 CacheManager 初始化");
        return cacheManager;
    }
    
    @Bean
    public Cache<String, Object> caffeineCache() {
        log.info("缓存配置 Cache 初始化");
        return Caffeine.newBuilder()
                // 设置最后一次写入或访问后经过固定时间过期
                .expireAfterWrite(600, TimeUnit.SECONDS)
                // 初始的缓存空间大小
                .initialCapacity(1000)
                // 缓存的最大条数
                .maximumSize(1000)
                .build();
    }
}

Caffeine配置参数说明:

initialCapacity=[integer]: 初始的缓存空间大小
maximumSize=[long]: 缓存的最大条数
maximumWeight=[long]: 缓存的最大权重
expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
weakKeys: 打开key的弱引用
weakValues:打开value的弱引用
softValues:打开value的软引用
recordStats:开发统计功能 注意:
expireAfterWrite和expireAfterAccess同事存在时,以expireAfterWrite为准。
maximumSize和maximumWeight不可以同时使用
weakValues和softValues不可以同时使用

注意: CacheManager 是使用注解形式时需要注入的Bean,Cache是在代码中显示使用时需要注入的,可以注入多个Bean,用名字区分,达到使用不通的缓存配置的效果。比如对过期时间有不通的要求,那么就可以注入两个过期时间不同的 CacheManager ,Bean的名字要做区分,在使用 @Cacheable 调用缓存时,便可以显示指定不同的 cacheManager。

步骤 3: 使用缓存

有两种使用缓存的方式:注解使用、代码显示使用

  • 注解使用

        // 获取缓存
        @GetMapping("/getCache")
        @Cacheable(value = "cache", key = "'key'")
        public String getCache() throws InterruptedException {
            Thread.sleep(3000);
            return "getCache";
        }
    
    	// 设置缓存
        @GetMapping("/setCache")
        @CachePut(value = "cache", key = "'key'")
        public String setCache() throws InterruptedException {
            Thread.sleep(3000);
            return "setCache";
        }
    
    	// 删除缓存
        @GetMapping("/delCache")
        @CacheEvict(value = "cache", key = "'key'")
        public String delCache() throws InterruptedException {
            Thread.sleep(3000);
            return "delCache";
        }
    

    注解使用说明:

    • @EnableCaching

      开启缓存功能,一般放在启动类上。

    • @CacheConfig

      当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames = {“cacheName”})注解在 class 之上来统一指定value的值,这时可省略value,如果你在你的方法依旧写上了value,那么依然以方法的value值为准。

    • @Cacheable

      根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。

      属性/方法名解释
      value缓存名,必填,它指定了你的缓存存放在哪块命名空间
      cacheNames与 value 差不多,二选一即可
      key可选属性,可以使用 SpEL 标签自定义缓存的key
      keyGeneratorkey的生成器。key/keyGenerator二选一使用
      cacheManager指定缓存管理器
      cacheResolver指定获取解析器
      condition条件符合则缓存
      unless条件符合则不缓存
      sync是否使用异步模式,默认为false
    • @CachePut

      使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据。一般用在新增方法上。

      属性/方法名解释
      value缓存名,必填,它指定了你的缓存存放在哪块命名空间
      cacheNames与 value 差不多,二选一即可
      key可选属性,可以使用 SpEL 标签自定义缓存的key
      keyGeneratorkey的生成器。key/keyGenerator二选一使用
      cacheManager指定缓存管理器
      cacheResolver指定获取解析器
      condition条件符合则缓存
      unless条件符合则不缓存
    • @CacheEvict

      使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上。

      属性/方法名解释
      value缓存名,必填,它指定了你的缓存存放在哪块命名空间
      cacheNames与 value 差不多,二选一即可
      key可选属性,可以使用 SpEL 标签自定义缓存的key
      keyGeneratorkey的生成器。key/keyGenerator二选一使用
      cacheManager指定缓存管理器
      cacheResolver指定获取解析器
      condition条件符合则缓存
      allEntries是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存
      beforeInvocation是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存
    • @Caching

      该注解可以实现同一个方法上同时使用多种注解。可从其源码看出:

      image-20240716171300420

  • 代码显示使用

        @Autowired
        private Cache<String, Object> cache;
    
        @GetMapping("/getCacheInfo")
        public void getCacheInfo() throws InterruptedException {
            String s = (String) cache.getIfPresent("key");
            if (s == null) {
                cache.put("key", "value");
                Thread.sleep(3000);
            }
            log.info("cache:{}", cache.getIfPresent("key"));
        }
    

    显示使用时需要注意处理并发读写,防止并发读写造成缓存不一致问题。

总结:使用Caffeine作为本地缓存能极大增加缓存数据的访问效率,提升读取性能。不过,本地缓存的使用受限于本地缓存的大小,所以面对缓存很大以及复杂的数据结构还是考虑用第三方的缓存服务,比如Redis。

关注不迷路。come on 在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1938546.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于重要抽样的主动学习不平衡分类方法ALIS

这篇论文讨论了数据分布不平衡对分类器性能造成的影响,并提出了一种新的有效解决方案 - 主动学习框架ALIS。 1、数据分布不平衡会影响分类器的学习性能。现有的方法主要集中在过采样少数类或欠采样多数类,但往往只采用单一的采样技术,无法有效解决严重的类别不平衡问题。 2、论…

【Datawhale AI 夏令营】CV图像竞赛——Deepfake攻防

【Datawhale AI 夏令营】CV图像竞赛——Deepfake攻防 从零入门CV图像竞赛(Deepfake攻防) 是 Datawhale 2024 年 AI 夏令营第二期 的学习活动&#xff08;“CV图像”方向&#xff09;&#xff0c;基于蚂蚁集团举办的“外滩大会-全球Deepfake攻防挑战赛”开展的实践学习 ​ 这几天…

Mysql深入讲解(索引、事务、锁机制)

一、MySQL索引 1、何为索引&#xff1f; MySQL中的索引是一种数据结构&#xff0c;用于加快对数据库表中数据的查询速度【查询速度提升】。它类似于书本目录&#xff0c;使得用户可以根据特定字段快速定位到所需的数据行&#xff0c;而无需扫描整个表。 2、索引分类 Hash索…

C 语言回调函数

回调函数的概念 您的理解是正确的。pFunCallBack 是一种函数指针类型&#xff0c;它定义了函数的签名&#xff08;即函数的参数类型和返回类型&#xff09;。当我们说 pFunCallBack pFun&#xff0c;我们是在声明一个变量 pFun&#xff0c;其类型是 pFunCallBack —— 即一个函…

【D3.js in Action 3 精译_018】2.4 向选择集添加元素

当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可视化最佳实践&#xff08;下&#xff09;1.4 本章小结 第二章…

RNN循环递归网络讲解与不掉包python实现

1.算法简介 参考论文&#xff1a;Elman J L. Finding structure in time[J]. Cognitive science, 1990, 14(2): 179-211.&#xff0c;谷歌被引次数超16000! 说到循环递归结构就不得不提到其鼻祖RNN网络。首先我们先对RNN有个初步的概念&#xff1a;想象一下&#xff0c;你正在…

[紧急!!!]20240719全球Windows10/11蓝屏问题,CrowdStrike导致的错误解决方案

文章目录 前言一、CrowdStrike是什么&#xff1f;二、PC解决方式&#xff08;网路上大神的方式&#xff0c;虚拟机测试过&#xff09;1.Windows PC 上 CrowdStrike BSOD 问题的官方解决方法&#xff1a;2.阻止CrowdStrick启动-命令行法3.阻止CrowdStrick启动-注册表法 三、AWS …

基于Matlab的数据可视化

基于Matlab的数据可视化 一、二维图形的绘制&#xff08;一&#xff09;基本图形函数&#xff08;1&#xff09;plot函数&#xff08;2&#xff09;fplot函数&#xff08;3&#xff09;其他坐标系的二维曲线 &#xff08;二&#xff09;图形属性设置&#xff08;1&#xff09;线…

对某次应急响应中webshell的分析

文章前言 在之前处理一起应急事件时发现攻击者在WEB应用目录下上传了webshell&#xff0c;但是webshell似乎使用了某种加密混淆手法&#xff0c;无法直观的看到其中的木马连接密码&#xff0c;而客户非要让我们连接webshell来证实此文件为后门文件且可执行和利用(也是很恼火&a…

数据结构与算法04二叉树|二叉排序树|AVL树

目录 一、二叉树(binary tree) 1、二叉树常见术语 2、二叉树常用的操作 2.1、初始化&#xff1a;与链表十分相似&#xff0c;先创建节点&#xff0c;然后构造引用/指针关系. 2.2、插入和删除操作 3、常见二叉树类型 3.1、满二叉树 3.2、完全二叉树&#xff08;complete b…

跳跃游戏Ⅱ - vector

55. 跳跃游戏 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:bool canJump(vector<int>& nums) {int n nums.size();int reach 0;for(int i 0; i < n; i){if(i > reach){return false;}reach max(inums[i], reach);}return true;} }; …

SpringBoot3 + Vue3 学习 Day 2

登入接口 和 获取用户详细信息的开发 学习视频登入接口的开发1、登入主逻辑2、登入认证jwt 介绍生成 JWT① 导入依赖② 编写代码③ 验证JWT 登入认证接口的实现① 导入 工具类② controller 类实现③ 存在的问题及优化① 编写拦截器② 注册拦截器③ 其他接口直接提供服务 获取用…

JVM(day4)类加载机制

类加载过程 加载 通过一个类的全限定名来获取定义此类的二进制字节流。 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。 在内存中生成一个代表这个类的java.lang.Class对象&#xff0c;作为方法区这个类的各种数据的访问入口。 验证 文件格式验证 元数…

LeetCode做题记录(第二天)647. 回文子串

题目&#xff1a; 647. 回文子串 标签&#xff1a;双指针 字符串 动态规划 题目信息&#xff1a; 思路一&#xff1a;暴力实现 我们直接for套for分割成一个个子串再判断&#xff0c;如果子串是回文子串&#xff0c;就1&#xff0c;最后得出结果 代码实现&#xff1a; cl…

C语言实例-约瑟夫生者死者小游戏

问题&#xff1a; 30个人在一条船上&#xff0c;超载&#xff0c;需要15人下船。于是人们排成一队&#xff0c;排队的位置即为他们的编号。报数&#xff0c;从1开始&#xff0c;数到9的人下船&#xff0c;如此循环&#xff0c;直到船上仅剩15人为止&#xff0c;问都有哪些编号…

Missing script:‘dev‘

场景&#xff1a; npm run dev 原因&#xff1a;没有安装依赖&#xff0c;可用镜像安装&#xff08;详见下图ReadMe 蓝色字体&#xff09;&#xff0c;没安装依赖可从package-lock.json文件是否存在看出&#xff0c;存在则有依赖 解决&#xff1a;

KMP算法(算法篇)

算法之KMP算法 KMP算法 概念&#xff1a; KMP算法是用于解决字符串匹配的问题的算法&#xff0c;也就是有一个文本串和一个模式串&#xff0c;求解这个模式串是否在文本串中出现或者匹配。相对于暴力求解&#xff0c;KMP算法使用了前缀表来进行匹配&#xff0c;充分利用了之…

【Vue3】从零开始编写项目

【Vue3】从零开始编写项目 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的…

神经网络模型实现(训练、测试)

目录 一、神经网络骨架&#xff1a;二、卷积操作&#xff1a;三、卷积层&#xff1a;四、池化层&#xff1a;五、激活函数&#xff08;以ReLU为例&#xff09;&#xff1a;六、模型搭建&#xff1a;七、损失函数、梯度下降&#xff1a;八、模型保存与加载&#xff1a;九、模型训…

Linux下安装JDK、Tomact、MySQL以及Nginx的超详细步骤

目录 1、为什么安装这些软件 2、安装软件的方式 3、安装JDK 3.1 下载Linux版本的JDK 3.2 将压缩包拖拽到Linux系统下 3.3 解压jdk文件 3.4 修改文件夹名字 3.5 配置环境变量 4、安装Tomcat 4.1 下载Tomcat 4.2 将Tomcat放入Linux系统并解压&#xff0c;步骤如上面的…