缓存技巧 · Spring Cache Caffeine 高性能缓存库

news2024/12/23 5:14:59

在这里插入图片描述

Caffeine 背景

Caffeine是一个高性能的Java缓存库,它基于Guava Cache进行了增强,提供了更加出色的缓存体验。Caffeine的主要特点包括:

高性能:Caffeine使用了Java 8最新的StampedLock乐观锁技术,极大地提高了缓存的并发吞吐量,使其成为一个高性能的Java缓存库。

内存友好:Caffeine支持自动驱逐缓存中的元素,以限制其内存占用。它还提供了灵活的构造器,可以创建具有不同特性的缓存,如自动加载元素、基于容量的驱逐、基于过期时间的驱逐等。

可扩展性强:Caffeine支持 JSR-107 - JCache_(Java临时缓存API (JSR-107),也称为JCache,是定义javax.cache API的规范。 该规范是在Java社区流程下开发的,其目的是为Java应用程序提供标准化的缓存概念和机制。 API使用简单,它被设计为缓存标准,是供应商中立的。)_和Guava适配器,提高了与其他缓存库和框架的集成度。

事件监听和多种过期策略:Caffeine提供了事件监听和多种过期策略,可以更好地优化和管理数据的缓存。这些功能不仅可以提升系统的性能表现,也能够有效地降低对底层资源的压力。

本地缓存:Caffeine是一个基于Java 8开发的提供了近乎最佳命中率的高性能缓存库。可以说是目前最优秀的本地缓存。

总之,Caffeine是一个功能强大、性能卓越的Java缓存库,适用于各种需要缓存的应用场景。

Caffeine 主要特点

Caffeine 是一个高性能的 Java 缓存库,它的主要特点包括:

  1. 速度:Caffeine 的性能非常高,它的速度通常比 ConcurrentHashMap 快很多。Caffeine 使用了高效的数据结构和并发算法,以及一些优化手段,如无锁操作、缓存行填充等,来提高性能。
  2. 自动垃圾回收:Caffeine 支持基于访问时间和写入时间的自动垃圾回收。当缓存中的数据超过了设定的过期时间,Caffeine 会自动将其从缓存中移除。
  3. 基于大小的回收:Caffeine 支持基于缓存大小的回收策略。当缓存中的数据量超过了设定的最大值,Caffeine 会自动回收最近最少使用的数据。
  4. 定时回收:Caffeine 支持定时回收策略,可以设置缓存中的数据在一定时间后被强制回收。
  5. 缓存统计:Caffeine 提供了丰富的缓存统计信息,如命中率、缓存大小等,帮助开发者了解缓存的使用情况。
  6. 灵活的配置:Caffeine 提供了丰富的配置选项,允许开发者根据需要定制缓存的行为。例如,可以设置缓存的最大大小、过期时间、回收策略等。
  7. 扩展性:Caffeine 支持自定义缓存实现,开发者可以根据需要扩展 Caffeine 的功能。
  8. 与 Spring Cache 集成:Caffeine 可以很容易地与 Spring Cache 集成,使得在 Spring 项目中使用缓存变得更加简单。
  9. 无阻塞操作:Caffeine 的大部分操作都是无阻塞的,这意味着它可以在高并发环境下提供更好的性能。
  10. 轻量级:Caffeine 是一个轻量级的库,它的依赖非常少,不会给项目带来额外的负担。

这些特点使得 Caffeine 成为了一个非常受欢迎的 Java 缓存库,尤其是在需要高性能和灵活配置的场景中。如果你正在寻找一个高性能的 Java 缓存库,Caffeine 值得一试。

更多关于 Caffeine 和 Spring Cache 的信息,可以查阅官方文档:

  • Caffeine: https://github.com/ben-manes/caffeine/wiki
  • Spring Cache: https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html__#cache

Caffeine 使用

Spring Cache 是 Spring 框架提供的一个缓存抽象,它允许开发者通过注解的方式轻松地使用缓存。Caffeine 是一个高性能的 Java 缓存库,它提供了诸如自动垃圾回收、基于大小的回收、定时回收等功能。

要在 Spring 中使用 Caffeine 作为缓存实现,需执行以下步骤:

添加依赖

在你的项目中,添加 Caffeine 和 Spring Cache 的依赖。可以在 pom.xml 文件中添加以下依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
   <groupId>com.github.ben-manes.caffeine</groupId>
   <artifactId>caffeine</artifactId>
</dependency>

配置 Caffeine

在你的 Spring Boot 配置类中,配置 Caffeine 缓存管理器:

创建了一个 CaffeineCacheManager Bean,并设置了 Caffeine 的一些基本属性,如过期时间和最大缓存大小。

import com.github.benmanes.caffeine.cache.Caffeine;
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;

@Configuration
public class CaffeineConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .expireAfterWrite(60, TimeUnit.SECONDS)
                .maximumSize(100));
        return cacheManager;
    }
}

可以在你的服务类中使用 Spring Cache 的注解来缓存数据。

我们使用了 @Cacheable 注解来缓存 getUserById 方法的结果。当方法被调用时,Spring 会先检查缓存中是否存在该用户,如果存在则直接返回缓存中的数据,否则才会调用方法并将结果存入缓存。例如:

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        // 模拟从数据库中获取用户数据
        return new User(id, "User " + id);
    }
}

多个缓存区域

在 Caffeine 中,你可以配置多个缓存区域,每个区域都有自己的配置和缓存数据。要配置多个缓存区域,你需要为每个区域创建一个 Cache 实例,并为它们分别配置。

以下是一个使用 Spring Boot 和 Caffeine 配置多个缓存区域的例子:

配置缓存区域

在你的 Spring Boot 配置类中,配置多个缓存区域:我们创建了一个 SimpleCacheManager Bean,并为其配置了两个缓存区域。每个缓存区域都有自己的名称、过期时间和最大缓存大小。

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CaffeineConfig {

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        List<CaffeineCache> caches = new ArrayList<>();

        // 配置第一个缓存区域
        Cache<Object, Object> cache1 = Caffeine.newBuilder()
                .expireAfterWrite(60, TimeUnit.SECONDS)
                .maximumSize(100)
                .build();
        caches.add(new CaffeineCache("cache1", cache1));

        // 配置第二个缓存区域
        Cache<Object, Object> cache2 = Caffeine.newBuilder()
                .expireAfterWrite(30, TimeUnit.SECONDS)
                .maximumSize(50)
                .build();
        caches.add(new CaffeineCache("cache2", cache2));

        cacheManager.setCaches(caches);
        return cacheManager;
    }
}

使用缓存区域

在你的服务类中使用 Spring Cache 的注解来缓存数据,并指定要使用的缓存区域:我们使用了 @Cacheable 注解来缓存 getUserByIdFromCache1 和 getUserByIdFromCache2 方法的结果,并分别指定了不同的缓存区域。

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Cacheable(value = "cache1", key = "#id")
    public User getUserByIdFromCache1(Long id) {
        // 模拟从数据库中获取用户数据
        return new User(id, "User " + id);
    }

    @Cacheable(value = "cache2", key = "#id")
    public User getUserByIdFromCache2(Long id) {
        // 模拟从数据库中获取用户数据
        return new User(id, "User " + id);
    }
}

Caffeine 常见机制

Notification on Eviction

Caffeine 提供了一种机制,允许你在缓存项被回收时接收通知,这被称为 “Notification on Eviction”。使用 removalListener 方法注册一个回调函数。当缓存项被回收时,这个回调函数会被调用。

以下是一个使用 Caffeine 的 “Notification on Eviction” 的例子:我们创建了一个 Caffeine 缓存,并使用 removalListener 方法注册了一个回调函数。当缓存项被回收时,这个回调函数会被调用,并打印出被回收的缓存项的键、值和回收原因。

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.RemovalListener;

import java.util.concurrent.TimeUnit;

public class CaffeineNotificationOnEvictionExample {

    public static void main(String[] args) throws InterruptedException {
        RemovalListener<String, String> removalListener = (key, value, cause) -> {
            System.out.println("Key: " + key + ", Value: " + value + ", Cause: " + cause);
        };

        Cache<String, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .maximumSize(100)
                .removalListener(removalListener)
                .build();

        cache.put("key1", "value1");
        cache.put("key2", "value2");

        // 等待一段时间,让缓存项过期
        Thread.sleep(60 * 1000);

        // 清理缓存
        cache.cleanUp();
    }
}

需要注意,“Notification on Eviction” 只在缓存项被主动回收时触发,而不是在缓存项被读取或写入时触发。

此外,“Notification on Eviction” 并不保证在所有情况下都能接收到通知,例如在缓存关闭或应用程序退出时,可能无法接收到通知。因此,在使用 “Notification on Eviction” 时,需要考虑到这些因素。

Cleanup

Caffeine 提供了一种机制,允许你手动触发缓存的清理操作,这被称为 “Cleanup”。使用 cleanUp 方法注册一个回调函数。当需要清理缓存时,可以调用 cleanUp 方法来触发回调函数。

以下是一个使用 Caffeine 的 “Cleanup” 的例子:我们创建了一个 Caffeine 缓存,并使用 removalListener 方法注册了一个回调函数。当缓存项被回收时,这个回调函数会被调用,并打印出被回收的缓存项的键、值和回收原因。

在这个例子中,我们使用 cleanUp 方法手动触发了缓存的清理操作。这会导致所有过期的缓存项被回收,并触发回调函数。

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.RemovalListener;

import java.util.concurrent.TimeUnit;

public class CaffeineCleanupExample {

    public static void main(String[] args) throws InterruptedException {
        RemovalListener<String, String> removalListener = (key, value, cause) -> {
            System.out.println("Key: " + key + ", Value: " + value + ", Cause: " + cause);
        };

        Cache<String, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .maximumSize(100)
                .removalListener(removalListener)
                .build();

        cache.put("key1", "value1");
        cache.put("key2", "value2");

        // 等待一段时间,让缓存项过期
        Thread.sleep(60 * 1000);

        // 手动触发缓存清理
        cache.cleanUp();
    }
}

需要注意,“Cleanup” 并不保证在所有情况下都能清理缓存。例如,在缓存关闭或应用程序退出时,可能无法清理缓存。因此,在使用 “Cleanup” 时,需要考虑到这些因素。

Enable Statistics

Caffeine 提供了一种机制,允许你启用缓存的统计信息收集功能,这被称为 “Enable Statistics”。在创建 Caffeine 缓存时,使用 recordStats 方法启用统计信息收集功能。启用统计信息收集功能后,使用 stats 方法获取缓存的统计信息。

以下是一个使用 Caffeine 的 “Enable Statistics” 的例子:我们创建了一个 Caffeine 缓存,并使用 recordStats 方法启用了统计信息收集功能。在缓存中添加了两个缓存项后,我们等待了一段时间,让缓存项过期。然后,我们使用 stats 方法获取了缓存的统计信息,并将其打印出来。

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.stats.CacheStats;

import java.util.concurrent.TimeUnit;

public class CaffeineEnableStatisticsExample {

    public static void main(String[] args) throws InterruptedException {
        Cache<String, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .maximumSize(100)
                .recordStats()
                .build();

        cache.put("key1", "value1");
        cache.put("key2", "value2");

        // 等待一段时间,让缓存项过期
        Thread.sleep(60 * 1000);

        // 获取缓存的统计信息
        CacheStats stats = cache.stats();
        System.out.println("Cache Stats: " + stats);
    }
}

需要注意,启用统计信息收集功能会增加缓存的开销,因此在生产环境中使用时需要谨慎。在开发和测试环境中,启用统计信息收集功能可以帮助你更好地了解缓存的使用情况,从而优化缓存的配置和使用。

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

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

相关文章

VisionPro - 基础 - 00 模板匹配技术和在VP中的使用 - PMAlign - PatMax - (3)

前言&#xff1a; 针对PatMax 的高级应用和原理&#xff0c;在这一节继续进行说明&#xff1a;这一节主要考虑的是PatMax模板匹配的原理&#xff1a; How PatMax Finds Patterns in an Image PatMax 模板匹配原理 1 Run-time Space When you search for a PatMax pattern in …

World of Warcraft [CLASSIC] International translation bug

internationalization i18n_getinternationalizationjs-CSDN博客 1&#xff09;国际化翻译不完整 Chance on melee and ranged critical strike to increase your attack power by 1262 for 10s. 2&#xff09;更新美酒节&#xff0c;服务器并发太高&#xff0c;被提出副本 Wo…

DataFrame生成excel后为什么多了一行数字

问题描述 python查询数据生成excel文件&#xff0c;生成的excel多了第一行数字索引&#xff0c;1,2,3,4,5...... 代码&#xff1a; df pd.DataFrame(data)df.to_excel(filename, sheet_name用户信息表, indexFalse) 解决&#xff1a; 原理也很简单&#xff0c;就是设置个参…

Java对象一口气讲完!φ(* ̄0 ̄)

Java Object类 Java面向对象设计 - Java Object类 Java在java.lang包中有一个Object类。 所有Java类都直接或间接扩展Object类。 所有Java类都是Object类的子类Object类是所有类的超类。 Object类本身没有超类。 Object类的引用变量可以保存任何类的对象的引用。 以下代…

python中ocr图片文字识别样例(一)

一、使用easyocr安装依赖 pip install easyocr pip install opencv-python-headless # 处理图像二、具体实现&#xff0c;此处有个缺陷&#xff0c;大家可以尝试解决下&#xff0c;识别的文字打印结果没问题&#xff0c;但是图片识别出现乱码&#xff1a; 2.1 具体识别的图片…

Springboot 文件上传下载相关问题

文章目录 关于Springboot 文件上传下载问题解决方案注意事项文件上传文件下载文件删除文件在线打开在写练习的时候&#xff0c;发现了一些小小的问题&#xff0c;已经在 上述代码中体现。① 代码路径碰到中文的时候&#xff0c;会有乱码&#xff0c;需要转换&#xff08;内容中…

【全网首发】2024华为杯数学建模ABCDEF选题方向+完整思路代码+数据集处理+可视化结果

2024华为杯研究生数学建模比赛ABCDEF选题分析 建议选哪道题&#xff1f; 点击链接加入群聊【2024华为杯数学建模助攻资料】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&kxtS4vwn3gcv8oCYYyrqd0BvFc7tNfhV7&authKeyedQFZne%2BzvEfLEVg2v8FOm%2BWNg1V%2Fiv3H…

KMP算法的实现

这是C算法基础-数据结构专栏的第二十六篇文章&#xff0c;专栏详情请见此处。 引入 KMP算法是一种可以快速查找某一字符串在一个文本中的所有出现的算法。 下面我们就来讲KMP算法的实现。 定义 Knuth–Morris–Pratt 算法&#xff0c;简称KMP算法&#xff0c;是由Knuth、Pratt…

2024华为杯数学建模竞赛E题

2024年中国研究生数学建模竞赛E题 高速公路应急车道紧急启用模型 高速公路拥堵现象的原因众多&#xff0c;除了交通事故外&#xff0c;最典型的就是部分路段出现瓶颈现象&#xff0c;主要原因是车辆汇聚&#xff0c;而拥堵后又容易蔓延。高速公路一些特定的路段容易形成堵点&…

云手机的便捷性和安全性体现在哪?

随着5G技术的迅速发展&#xff0c;云手机在游戏、电商以及新媒体营销等领域中的应用日益广泛。它不仅能够显著降低成本、提升效率&#xff0c;还随着边缘计算和云技术的进步&#xff0c;展现出无限的增长潜力。 云手机的便捷性体现在哪里&#xff1f; 云手机的便捷性毋庸置疑。…

煤矿智慧矿井数据集 (1.煤矿采掘工作面智能分析数据集2.煤矿井下钻场智能分析数据集 )

智慧矿井智能分析数据集 数据1&#xff1a;数据1包含煤矿采掘工作面工人安全帽检测&#xff0c;工人行为检测&#xff08;行走&#xff0c;站立&#xff0c;坐&#xff0c;操作&#xff0c;弯腰&#xff0c;靠&#xff0c;摔&#xff0c;爬&#xff09;&#xff0c;液压支撑防护…

C++ | Leetcode C++题解之第421题数组中两个数的最大异或值

题目&#xff1a; 题解&#xff1a; struct Trie {// 左子树指向表示 0 的子节点Trie* left nullptr;// 右子树指向表示 1 的子节点Trie* right nullptr;Trie() {} };class Solution { private:// 字典树的根节点Trie* root new Trie();// 最高位的二进制位编号为 30static…

en造数据结构与算法C# 用Unity实现简单的群组行为算法 之 对齐

en造数据结构与算法C# 用Unity实现简单的群组行为算法 之 聚集-CSDN博客 en造数据结构与算法C# 用Unity实现简单的群组行为算法 之 聚集-CSDN博客 演示 思路 1.检测 自然是沿用前两节的检测范围 2.对齐朝向 对齐朝向就是邻居鸟的forward加起来再除总数得到平均数 3.对齐…

企业急于采用人工智能,忽视了安全强化

对主要云提供商基础设施上托管的资产的安全分析显示&#xff0c;许多公司为了急于构建和部署 AI 应用程序而打开安全漏洞。常见的发现包括对 AI 相关服务使用默认且可能不安全的设置、部署易受攻击的 AI 软件包以及不遵循安全强化指南。 这项分析由 Orca Security 的研究人员进…

关于机器学习和深度学习的区别有哪些?

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于机器学习和深度学习区别的相关内容&…

Altium Designer(AD)百度云下载与安装(附安装步骤)

在我们日常使用当中&#xff0c;Altium designer常常也被简称为AD&#xff0c;是一款一体化的电子产品开发系统软件&#xff0c;主要运行在Windows操作系统上。 我们通过Altium designer把原理图设计、电路仿真、PCB绘制编辑、拓扑逻辑自动布线、信号完整性分析和设计输出等技…

企业为什么要做算法备案?

企业为什么要做算法备案&#xff1f; 在数字经济迅速发展的今天&#xff0c;算法已成为推动各行各业创新发展的核心动力。鉴于此&#xff0c;国家层面正积极构建完善的监管框架&#xff0c;旨在促进算法应用的健康发展&#xff0c;确保其在法治轨道上运行。 近期&#xff0c;一…

揭开数据能力的神秘面纱

在当今数字化时代&#xff0c;数据已成为企业和组织的重要资产。拥有强大的数据能力&#xff0c;能够帮助企业更好地理解市场、客户和业务&#xff0c;从而做出更明智的决策。然而&#xff0c;数据能力究竟是什么&#xff1f;它包含哪些方面&#xff1f;又如何提升呢&#xff1…

银河麒麟桌面操作系统V10(SP1)ssh服务安装与配置

在国产化的大背景下,各种国产操作系统逐步进入运维人员的视野,ssh作为linux远程连接工具,是运维人员必需的工具之一。本文主要介绍在银河麒麟桌面操作系统V10(SP1)上安装和配置ssh服务。 准备工作 1、查看操作系统信息 cat /etc/os-release 笔者操作系统为银河麒麟桌面操…

一款能够管控企业计算机的安全系统 | 企业终端安全管控 | 天锐DLP数据安全

天 锐 DLP可帮助企业规范对电脑计算机的使用管理&#xff0c;对USB存储设备、终端外节设备、桌面壁纸进行统一管控&#xff0c;支持限制控制面板、计算机管理、系统下的相关功能选项的使用。 【地址&#xff1a;点击了解天锐股份数据安全产品】 1.计算机设置 天锐DLP可对计算…