Caffeine 本地高速缓存工具类

news2024/12/23 8:33:23

目录

Caffeine工具类方式

SpringBoot 整合 Caffeine 缓存 (SpringCache模式)

驱逐策略

开发使用


Caffeine是一种高性能的缓存库,是基于Java 8的最佳(最优)缓存框架,性能各方面优于guava。

Caffeine工具类方式

原文链接:https://www.cnblogs.com/wudiffs/p/11585757.html

代码仓库如下:

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

 代码详细示例如下:

public class CaffeineCacheManagerService {

    private static LoadingCache<String, CacheVO> cache;

    private static AsyncLoadingCache<String, CacheVO> asyncCache;

    private static AsyncLoadingCache<String, CacheVO> asyncCache1;

    private static ExecutorService executorService = new ThreadPoolExecutor(8, 8, 8, TimeUnit.SECONDS, new
            LinkedBlockingQueue<Runnable>(1204));

    static {
        cache = Caffeine.newBuilder()
                // 初始化缓存长度
                .initialCapacity(1024 * 10)
                // 最大长度
                .maximumSize(1024 * 10)
                // 更新策略
                .refreshAfterWrite(10, TimeUnit.SECONDS)
                // 设置缓存的过期时间
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .build(new CacheLoader<String, CacheVO>() {

                    // 同步加载
                    @CheckForNull
                    @Override
                    public CacheVO load(@Nonnull String key) throws Exception {
                        return createCacheVO(key);
                    }

                    // getAll将会对缓存中没有值的key分别调用CacheLoader.load方法来构建缓存的值。
                    // 我们可以重写CacheLoader.loadAll方法来提高getAll的效率。
                    @Nonnull
                    @Override
                    public Map<String, CacheVO> loadAll(@Nonnull Iterable<? extends String> keys) throws Exception {
                        return createBatchCacheVOs(keys);
                    }
                });

        // 异步加载 同步load写法,最后也会转异步
        asyncCache = Caffeine.newBuilder()
                .maximumSize(1024 * 10)
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .buildAsync(new CacheLoader<String, CacheVO>() {
                    @CheckForNull
                    @Override
                    public CacheVO load(@Nonnull String key) throws Exception {
                        return createCacheVO(key);
                    }

                    @Nonnull
                    @Override
                    public Map<String, CacheVO> loadAll(@Nonnull Iterable<? extends String> keys) {
                        return createBatchCacheVOs(keys);
                    }
                });

        // 异步加载 异步load写法
        asyncCache1 = Caffeine.newBuilder()
                .maximumSize(1024 * 10)
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .buildAsync(new AsyncCacheLoader<String, CacheVO>() {
                    @Nonnull
                    @Override
                    public CompletableFuture<CacheVO> asyncLoad(@Nonnull String key, @Nonnull Executor executor) {
                        return asyncCreateCacheVO(key, executor);
                    }

                    @Nonnull
                    @Override
                    public CompletableFuture<Map<String, CacheVO>> asyncLoadAll(@Nonnull Iterable<? extends String> keys, @Nonnull Executor executor) {
                        return asyncCreateBatchCacheVOs(keys, executor);
                    }
                });

    }

    public static CompletableFuture<CacheVO> asyncCreateCacheVO(String key, Executor executor) {
        return CompletableFuture.supplyAsync(() -> createCacheVO(key), executor);
    }

    public static CompletableFuture<Map<String, CacheVO>> asyncCreateBatchCacheVOs(Iterable<? extends String> keys, Executor executor) {
        return CompletableFuture.supplyAsync(() -> createBatchCacheVOs(keys), executor);
    }

    public static CacheVO createCacheVO(String key) {
        return new CacheVO(key);
    }

    public static Map<String, CacheVO> createBatchCacheVOs(Iterable<? extends String> keys) {
        Map<String, CacheVO> result = new HashMap<>();
        for (String key : keys) {
            result.put(key, new CacheVO(key));
        }
        return result;
    }

    public static void main(String[] args) throws Exception {

        CacheVO cacheVO1 = cache.get("AA");

        List<String> list = new ArrayList<>();
        list.add("BB");
        list.add("CC");
        Map<String, CacheVO> map = cache.getAll(list);

        // 如果有缓存则返回;否则运算、缓存、然后返回,整个过程是阻塞的
        // 即使多个线程同时请求该值也只会调用一次Function方法
        CacheVO cacheVO2 = cache.get("DD", (k) -> createCacheVO(k));
        System.out.println(JSON.toJSONString(cacheVO2));
        // 单个清除
        cache.invalidate("AA");
        // 批量清除
        cache.invalidateAll(list);
        // 全部清除
        cache.invalidateAll();

        // 返回一个CompletableFuture
        CompletableFuture<CacheVO> future = asyncCache.get("EE");
        CacheVO asyncCacheVO = future.get();
        System.out.println(JSON.toJSONString(asyncCacheVO));
        // 返回一个CompletableFuture<MAP<>>
        CompletableFuture<Map<String, CacheVO>> allFuture = asyncCache.getAll(list);
        Map<String, CacheVO> asyncMap = allFuture.get();
        System.out.println(JSON.toJSONString(asyncMap));

        CompletableFuture<CacheVO> future1 = asyncCache1.get("FF");
        CacheVO asyncCacheVO1 = future1.get();
        System.out.println(JSON.toJSONString(asyncCacheVO1));
        CompletableFuture<Map<String, CacheVO>> allFuture1 = asyncCache1.getAll(list);
        Map<String, CacheVO> asyncMap1 = allFuture.get();
        System.out.println(JSON.toJSONString(asyncMap1));
    }

}

或者使用下发方式实现Caffeine 工具类

支持同步、异步读写缓存实现

import com.github.benmanes.caffeine.cache.AsyncCache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

public class CaffeineCacheUtils {
    private static com.github.benmanes.caffeine.cache.Cache<Object, Object> syncCache;
    private static AsyncCache<Object, Object> asyncCache;

    private CaffeineCacheUtils() {
    }

    public static void initCache() {
        syncCache = Caffeine.newBuilder()
                .initialCapacity(100)
                .maximumSize(1000)
                .expireAfterWrite(30, TimeUnit.MINUTES)
                .build();

        asyncCache = Caffeine.newBuilder()
                .initialCapacity(100)
                .maximumSize(1000)
                .expireAfterWrite(30, TimeUnit.MINUTES)
                .buildAsync();
    }

    public static void putSync(Object key, Object value) {
        syncCache.put(key, value);
    }

    public static Object getSync(Object key) {
        return syncCache.getIfPresent(key);
    }

    public static CompletableFuture<Object> getAsync(Object key, Executor executor) {
        return asyncCache.get(key, k -> CompletableFuture.supplyAsync(() -> fetchDataFromDataSource(k), executor));
    }

    public static CompletableFuture<Void> putAsync(Object key, Object value, Executor executor) {
        return asyncCache.put(key, CompletableFuture.completedFuture(value), executor);
    }

    public static void removeSync(Object key) {
        syncCache.invalidate(key);
    }

    public static void clearSync() {
        syncCache.invalidateAll();
    }

    private static Object fetchDataFromDataSource(Object key) {
        // 模拟从数据源获取数据的操作
        // 这里可以根据具体业务需求进行实现
        return null;
    }
}

 

SpringBoot 整合 Caffeine 缓存 (SpringCache模式)

原文链接:https://blog.csdn.net/Listening_Wind/article/details/110085228

添加依赖:

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

 缓存配置:

 如果使用了多个cahce,比如redis、caffeine等,必须指定某一个CacheManage为@primary

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.assertj.core.util.Lists;
import org.springframework.cache.CacheManager;
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 org.springframework.context.annotation.Primary;

import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Wxy
 * @Date: 2020/11/7 16:56
 * @Description
 */
@Configuration
@EnableCaching // 开启缓存,否则无效
public class CaffeineConfig {

    /**
     * 创建基于Caffeine的Cache Manager
     *
     * @return
     */
    @Bean
    @Primary
    public CacheManager caffeineCacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        ArrayList<CaffeineCache> caches = Lists.newArrayList();
        Map<String, Object> map = getCacheType();
        for (String name : map.keySet()) {
            caches.add(new CaffeineCache(name, (Cache<Object, Object>) map.get(name)));
        }
        cacheManager.setCaches(caches);
        return cacheManager;
    }

    /**
     * 初始化自定义缓存策略
     *
     * @return
     */
    private static Map<String, Object> getCacheType() {
        Map<String, Object> map = new ConcurrentHashMap<>();
        map.put("name1", Caffeine.newBuilder().recordStats()
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .maximumSize(100)
                .build());
        map.put("name2", Caffeine.newBuilder().recordStats()
                .expireAfterWrite(50, TimeUnit.SECONDS)
                .maximumSize(50)
                .build());
        return map;
    }
}

驱逐策略

基于大小的回收策略有两种方式:基于缓存大小,基于权重,基于时间。
maximumSize : 根据缓存的计数进行驱逐 同一缓存策略 缓存的数据量,以访问先后顺序,以最大100为例,超出100驱逐最晚访问的数据缓存。
maximumWeight : 根据缓存的权重来进行驱逐(权重只是用于确定缓存大小,不会用于决定该缓存是否被驱逐)。
maximumWeight与maximumSize不可以同时使用。

Caffeine提供了三种定时驱逐策略:

expireAfterAccess(long, TimeUnit):在最后一次访问或者写入后开始计时,在指定的时间后过期。假如一直有请求访问该key,那么这个缓存将一直不会过期。
expireAfterWrite(long, TimeUnit): 在最后一次写入缓存后开始计时,在指定的时间后过期。
expireAfter(Expiry): 自定义策略,过期时间由Expiry实现独自计算。
缓存的删除策略使用的是惰性删除和定时删除。这两个删除策略的时间复杂度都是O(1)

开发使用

主要基于Spring缓存注解@Cacheable、@CacheEvict、@CachePut的方式使用

  • @Cacheable :改注解修饰的方法,若不存在缓存,则执行方法并将结果写入缓存;若存在缓存,则不执行方法,直接返回缓存结果。
  • @CachePut :执行方法,更新缓存;该注解下的方法始终会被执行。
  • @CacheEvict :删除缓存
  • @Caching 将多个缓存组合在一个方法上(该注解可以允许一个方法同时设置多个注解)
  • @CacheConfig 在类级别设置一些缓存相关的共同配置(与其它缓存配合使用)

注意 :@Cacheable 默认使用标@primary 注释的CacheManage

/**
 * 先查缓存,如果查不到,执行方法体并将结果写入缓存,若查到,不执行方法体,直接返回缓存结果
 * @param id
 */
@Cacheable(value = "name1", key = "#id", sync = true)
public void getUser(long id){
   //TODO 查找数据库
}

/**
 * 更新缓存,每次都会执行方法体
 * @param user
 */
@CachePut(value = "name1", key = "#user.id")
public void saveUser(User user){
   //todo 保存数据库
}

/**
 * 删除
 * @param user
 */
@CacheEvict(value = "name1",key = "#user.id")
public void delUser(User user){
   //todo 保存数据库
}

 参考博客:https://www.cnblogs.com/wudiffs/p/11585757.html

(23条消息) SpringBoot 集成 Caffeine(咖啡因)最优秀的本地缓存_springboot caffeine_Listening_Wind的博客-CSDN博客https://blog.csdn.net/Listening_Wind/article/details/110085228

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

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

相关文章

脉蜂:Django + Flutter 开发的进销存管理系统【已开源】

项目说明 小规模零售&#xff08;包括电商&#xff09;跟大规模零售企业的差别在哪里呢&#xff1f; 以我当前的认知来看&#xff0c;小规模零售跟大规模零售企业的差别更多的是在供应链管理、进销存管控上面产生的。如果有一个工具&#xff0c;能够帮他们减少这方面的差异&…

我们拆了一款Tof+AI避障的扫地机,小米铁蛋铁大机器人同款

追觅W10 Pro是2022年初推出的新品&#xff0c;相较前一代W10&#xff0c;两者间最大的区别是将LDS避障升级为了TofAI避障&#xff0c;扫地机本体前脸像给W10开了“大眼特效”的传感器和摄像头就是机械避障升级的最佳佐证。 在外观上扫地机还是延续了以往的设计&#xff0c;顶部…

ReactRouterDom-v5v6用法与异同

本文作者系360奇舞团前端开发工程师 简介&#xff1a; React Router Dom是React.js中用于实现路由功能的常用库。在React应用中&#xff0c;路由可以帮助我们管理页面之间的导航和状态&#xff0c;并实现动态加载组件。本文将深入探讨React Router Dom的两个主要版本&#xff1…

​一文学会iOS画中画浮窗

本文字数&#xff1a;11934字 预计阅读时间&#xff1a;40分钟 背景 之前有看到有人用画中画实现时分秒的计时&#xff0c;顺手收藏了&#xff0c;一直没来及看。最近使用《每日英语听力》&#xff0c;突然发现它用画中画实现了听力语句的显示&#xff0c;顿时来了兴趣&#xf…

超线程技术

超线程&#xff08;HT, Hyper-Threading&#xff09;是英特尔研发的一种技术&#xff0c;于2002年发布。超线程技术原先只应用于Xeon 处理器中&#xff0c;当时称为“Super-Threading”。之后陆续应用在Pentium 4 HT中。早期代号为Jackson。 [1] 通过此技术&#xff0c;英特尔实…

Golang每日一练(leetDay0077) 存在重复元素、天际线问题

目录 217. 存在重复元素 Contains Duplicate &#x1f31f; 218. 天际线问题 The Skyline Problem &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 …

PyTorch-torchvision

1. 以Torchvision中的CIFAR10为例 dataset.py Ps&#xff1a;如果是从其他地方下载的gz文件&#xff0c;直接建立一个dataset文件夹然后将gz文件放进去&#xff0c;再运行。 import torchvisiontrain_set torchvision.datasets.CIFAR10(root"./dataset", trainTr…

SpringCloud Alibaba Nacos

SpringCloud Alibaba Nacos Nacos 基础 1 官网 1.1 https://github.com/alibaba/Nacos 2 Nacos 是什么&#xff1f; 2.1 一句话: Nacos 就是注册中心[替代Eureka]配置中心[替代Config] 2.2 Nacos&#xff1a;Dynamic Naming and Configuration Service 2.3 Nacos&#xff…

数据结构---二叉树(C语言)

二叉树 1. 二叉树1.1 二叉树的遍历1.1.1二叉树前中后序遍历&#xff08;递归版&#xff09;1.1.2 层序遍历 1.2 二叉树的其他相关接口1.2.1 求二叉树的结点数量1.2.2 求叶子结点个数1.2.3 求树高1.2.4 求第k层结点个数1.2.5 查找二叉树值为k的结点 1. 二叉树 空树非空&#xff…

跨境DNS解析失败问题解决

新钛云服已累计为您分享748篇技术干货 问题 公司使⽤的是阿⾥云基础设施&#xff0c;DNS解析使⽤的是境外的Akamai作为域名的DNS解析服务商。 当前有部分应⽤需要被第三⽅应⽤调⽤&#xff0c;同时也有主动调⽤第三⽅应⽤的需求。最近突发了很多调⽤失败问题。 应⽤调⽤失败&am…

YB时代,正寻找新的数据支点

每个人可能都想过这样一些问题&#xff1a;我们的地球&#xff0c;能够承载多少人口&#xff1f;地球上的石油和煤炭能用多久&#xff1f;碳排放的极限在哪里&#xff1f; 但你有没有想过&#xff0c;我们的地球&#xff0c;能够承载多少数据&#xff1f; 根据《数据存储2030白…

手把手教你打造自己的 AI 虚拟主播

零、写在前面一、 准备环境二、配置软件环境2.1 OBS 安装2.2. VTube Studio 安装 三、开启 B 站直播四、开启 AI 主播五、直播最终效果 零、写在前面 AI 直播在近年来得到了快速的发展和普及&#xff0c;它已经成为了直播平台的重要组成部分。目前&#xff0c;许多知名的直播平…

「读书感悟系列」生命的礼物 · 关于爱、死亡及存在的意义

作者 | gongyouliu 编辑 | gongyouliu 最近花了不到一周时间看完了著名的团体心理治疗大师欧文D.亚隆和他的妻子玛丽莲亚隆合著的这本『生命的礼物 关于爱、死亡及存在的意义』。这本书非常特别&#xff0c;这是玛丽莲在87岁得癌症后跟丈夫一起合作的&#xff0c;每人写一章&a…

URLConnection(二)

文章目录 1. 缓存2. Java的Web缓存 1. 缓存 Web浏览器会缓存页面和图片&#xff0c;将资源缓存在本地&#xff0c;每次需要时会从缓存中重新加载&#xff0c;而不是每次都请求远程服务器。一些HTTP首部&#xff08;包括Expires和Cache-Control&#xff09;可以控制首部。默认情…

OJ练习第116题——二进制矩阵中的最短路径(BFS)

二进制矩阵中的最短路径 力扣链接&#xff1a;1091. 二进制矩阵中的最短路径 题目描述 给你一个 n x n 的二进制矩阵 grid 中&#xff0c;返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径&#xff0c;返回 -1 。 二进制矩阵中的 畅通路径 是一条从 左上角 单元格&am…

记一次Redis消息订阅序列化和反序列化的错误

1、使用的SpringBoot&#xff1b; 2、Redis的Config配置了JSON序列化&#xff0c;覆盖JDK序列化&#xff0c;便于中文查看&#xff0c;配置文件使用ConditionalOnProperty断言&#xff1b; 3、Nacos动态配置&#xff1b; 解决思路&#xff1a; 1、查看Redis中存入的数据乱码&am…

最佳WP Grid Builder评测:灵活的网格和过滤器

当您坐下来观看足球比赛时&#xff0c;您从一英里外都很容易看到超级巨星。 时尚而精致的比赛让他们与众不同&#xff0c;并且比赛的结果经常改变。球迷和经理们都喜欢他们&#xff0c;因为当他们踢球时&#xff0c;他们处于绝对最佳状态。 这同样适用于音乐界的巨星。通常&a…

Go中的异常处理(基础)

Go 中异常处理 主要掌握 一下几个方面: 掌握error接口掌握defer延迟掌握panic及recover error接口 error是指程序中出现不正常的情况,从而导致程序无法正常运行; go中为错误的类型提供了简单的错误处理机制 go中error的源码: // The error built-in interface type is t…

舵机云台实现追踪球形目标功能

1. 功能说明 在样机舵机云台上安装一个摄像头&#xff0c;本文示例将实现舵机云台追踪球形物体的功能。 2. 电子硬件 在这个示例中&#xff0c;我们采用了以下硬件&#xff0c;请大家参考&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09;‍ 扩展板 Bi…

Linux之创建进程、查看进程、进程的状态以及进程的优先级

文章目录 前言一、初识fork1.演示2.介绍3.将子进程与父进程执行的任务分离4.多进程并行 二、进程的状态1.进程的状态都有哪些&#xff1f;2.查看进程的状态2.运行&#xff08;R&#xff09;3.阻塞4.僵尸进程&#xff08;Z&#xff09;1.僵尸状态概念2.为什么要有僵尸状态&#…