Caffeine cache实现本地缓存(简单又清楚)

2023-05-16

Caffeine cache实现本地缓存题

  • 缓存填充策略
    •  手动加载
        •  介绍:
        •  使用方式:
    •  同步加载
        •  介绍:
        •  使用方式:
    •  异步加载
        •  介绍:
        •   注意: 异步和同步使用方式相似, 这里的话主要写一下创建和异步转同步
        •  使用方式:
  • 过期策略
    •  基于大小过期
        •   介绍:当缓存超出后,使用W-TinyLFU算法进行缓存淘汰处理
        •   使用方式:
    •  基于权重过期
        •   介绍:
        •   使用方式:
    •  基于时间过期
        •   介绍:
        •   使用方式:
    •  基于引用回收
        •   介绍:
        •   使用方式:
  • 基本使用
    •  手动删除
        •   使用方式:
    •  自动刷新
        •   使用方式:
    •  移除通知
        •   使用方式:
    •  外部存储
        •   使用方式:
    •  统计缓存使用情况
        •   使用方式:
  • 实例整合
    •  编码方式
        •   使用方式:
    •  注解方式(整合SpringBoot的cache)
        •   介绍:
        •   使用方式:
          •    @Cacheable注解:
          •    @CachePut注解:
          •    @CacheEvict注解:
          •    @CacheConfig注解:
          •    @Caching注解:
  • 简易缓存工具类

缓存填充策略

介绍:缓存的填充方式有三种,手动、同步和异步

 手动加载

 介绍:

手动控制缓存的增删改处理,主动增加、获取以及依据函数式更新缓存,底层使用ConcurrentHashMap进行节点存储,因此get方法是安全的。批量查找可以使getAllPresent()方法或者带填充默认值的getAll()方法

 使用方式:

@Test
void test1() {
  com.github.benmanes.caffeine.cache.@NonNull Cache<String, String> cache = Caffeine.newBuilder()
       // 最大数量
       .maximumSize(100)
       // 设置缓存策略在1天未写入过期缓存
       .expireAfterAccess(1, TimeUnit.DAYS)
       .build();
  // 存入缓存
  cache.put("cl", "cl");
  // 根据键值获取缓存
  System.out.println(cache.getIfPresent("cl"));
  // 根据键值获取缓存, 如果为空则调用后面的参是
  System.out.println(cache.get("abc", this::buildLoader));
  // 根据键值清除缓存
  cache.invalidate("abc");
  System.out.println(cache.getIfPresent("abc"));
}
// 缓存后面执行的方法
 String buildLoader(String k) {
  return k + "+default";
}

 同步加载

 介绍:

LoadingCache对象进行缓存的操作,使用CacheLoader进行缓存存储管理。 批量查找可以使用getAll()方法。 默认情况下, getAll()将会对缓存中没有值的key分别调用CacheLoader.load方法来构建缓存的值(build中的表达式)。我们可以重写CacheLoader.loadAll方法来提高getAll()的效率。

 使用方式:

@Test
void test1() {
    LoadingCache<String, String> loadingCache = Caffeine.newBuilder()
         .maximumSize(100)
         .expireAfterAccess(1, TimeUnit.DAYS)
         // getAll将会对缓存中, 没有值的key分别调用CacheLoader.load方法来构建缓存的值
          .build(this :: buildLoader);
    // 存储要添加的缓存
     List<String> keys = new ArrayList<>();
    keys.add("cl");
    keys.add("b");
    keys.add("c");
    keys.add("d");
    // 返回一个map
    Map<String, String> cacheAll = loadingCache.getAll(keys);
    System.out.println(cacheAll.get("b"));
    System.out.println(cacheAll.get("c"));
    System.out.println(cacheAll.get("a"));
}
// 缓存后面执行的方法
 String buildLoader(String k) {
  return k + "+default";
}
 

 异步加载

 介绍:

AsyncLoadingCache对象进行缓存管理,get()返回一个CompletableFuture对象,默认使用ForkJoinPool.commonPool()来执行异步线程,但是我们可以通过Caffeine.executor(Executor) 方法来替换线程池
在这里插入图片描述

  注意: 异步和同步使用方式相似, 这里的话主要写一下创建和异步转同步

 使用方式:

@Test
void test1() {
  AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
       .maximumSize(100)
       .expireAfterAccess(1,TimeUnit.DAYS)
       .buildAsync(k-> this.buildLoaderAsync(k).get());

  try {
    System.out.println(asyncLoadingCache.get("123").get());
  } catch (Exception e) {
    e.printStackTrace();
  }
}
// 类似同步的load
CompletableFuture<String> buildLoaderAsync(String k) {
  return CompletableFuture.supplyAsync(() -> k + "buildLoaderAsync");
}
转换使用方式:
AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
    .maximumSize(100)
    .expireAfterAccess(1,TimeUnit.DAYS)
    .buildAsync(k -> this.buildLoaderAsync(k).get());
// 异步转同步
LoadingCache<String, String> cache = asyncLoadingCache.synchronous();
System.out.println("------------");
System.out.println(cache.get("dd")); 

过期策略

介绍:

Caffeine的缓存清除是惰性的,可能发生在读请求后或者写请求后
比如说有一条数据过期后,不会立即删除,可能在下一次读/写操作后触发删除(类比于redis的惰性删除)。
如果读请求和写请求比较少,但想要尽快的删掉cache中过期的数据的话,
可以通过增加定时器的方法,定时执行cache.cleanUp()方法(异步方法,可以等待执行),触发缓存清除操作。

 基于大小过期

  介绍:当缓存超出后,使用W-TinyLFU算法进行缓存淘汰处理

  使用方式:

  maximumSize()方法,参数是缓存中存储的最大缓存条目,当添加缓存时达到条目阈值后,将进行缓存淘汰操作
  // 使用方式 
    AsyncLoadingCache<String, String> asyncLoadingCache = Caffeine.newBuilder()
       .maximumSize(100)

 基于权重过期

  介绍:

通过权重来计算,每个实体都有不同的权重,总权重到达最高时淘汰实体。
weigher()方法可以指定缓存所占比重,maximumWeight()方法指定最大的权重阈值,当添加缓存超过规定权重后,进行数据淘汰

  使用方式:

com.github.benmanes.caffeine.cache.@NonNull LoadingCache<String, String> cache = Caffeine.newBuilder()
    .maximumWeight(10)
    .weigher(new Weigher<Object, Object>() {

       @Override
       public @NonNegative int weigh(@NonNull Object o, @NonNull Object o2) {
         System.out.println("key" + o + "value" + o2);
         return 5;
       }
    })
    .build(this::buildLoader);
List<String> list = Lists.newArrayList("c1", "c2", "c3");
cache.put(list.get(0), list.get(0));
System.out.println(list.get(0) + "--" + cache.get(list.get(0)));
cache.put(list.get(1), list.get(1));
System.out.println(list.get(1) + "---" + cache.get(list.get(1)));
System.out.println(cache.getAll(list));

 基于时间过期

  介绍:

expireAfterAccess():缓存访问后,一定时间失效;即最后一次访问或者写入开始时计时。
expireAfterWrite():缓存写入后,一定时间失效;以写入缓存操作为准计时。(在最后一次写入缓存后开始计时,在指定的时间后过期。)
expireAfter():自定义缓存策略,满足多样化的过期时间要求。
这里只展示after, 其他的话 使用方式大致相同,自己动手试试
注意:当expireAfterAccess和expireAfterWrite同时存在时,只有expireAfterWrite有效

  使用方式:

com.github.benmanes.caffeine.cache.@NonNull LoadingCache<String, String> cache = Caffeine.newBuilder()
    .expireAfter(new Expiry<Object, Object>() {
       // 创建后过期
       @Override
       public long expireAfterCreate(@NonNull Object o, @NonNull Object o2, long l) {
         return 1;
       }
       // 更新后过期
       @Override
       public long expireAfterUpdate(@NonNull Object o, @NonNull Object o2, long l, @NonNegative long l1) {
         return 1;
       }
       // 读取后过期
       @Override
       public long expireAfterRead(@NonNull Object o, @NonNull Object o2, long l, @NonNegative long l1) {
         return 1;
       }
    }).build(this::buildLoader);
 

 基于引用回收

  介绍:

在这里插入图片描述

  使用方式:

在这里插入图片描述

基本使用

 手动删除

  使用方式:

在这里插入图片描述

 自动刷新

  使用方式:

refreshAfterWrite:这里设置的是1分钟后自动刷新
在这里插入图片描述

 移除通知

  使用方式:

在这里插入图片描述

 外部存储

  使用方式:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

 统计缓存使用情况

  使用方式:

在这里插入图片描述

实例整合

 编码方式

  使用方式:

1、缓存配置类

@Configuration
public class CacheConfig {
  @Bean
  public Cache<String, Object> caffeineCache() {
    return Caffeine.newBuilder()
         // 设置最后一次写入或访问后经过固定时间过期
          .expireAfterWrite(60, TimeUnit.SECONDS)
         // 初始的缓存空间大小
          .initialCapacity(100)
         // 缓存的最大条数
          .maximumSize(1000)
         .build();
  }
}

2、使用
注意:这里我只写了存入的写法, 如果要获取缓存,用cache的get缓存我们存储的key就可以了。
如:

// 以下代码的具体含义请看文章, 文章都有介绍,如果没有 可以评论 我会给你进行解答
cache.put(1,"测试缓存")
// 获取缓存
cache.get("1");
// 如果你使用get爆红, 那可能是因为你没有填写第二个,那么你可以这样做
cache.get("1", value -> value);
// 或者
cache.asMap().get("1");

示例:

private final Cache<Object, Object> cache;
public FeedbackServiceImpl( Cache<Object, Object>  cache) {
  this.cache = cache;
}
public void insertFeedBack(Feedback feedback) {
  int i = feedbackMapper.insert(feedback);
  cache.put(feedback.getId(), feedback);
}

注意:如果你只是简单的使用, 你可以使用末文的缓存工具类

 注解方式(整合SpringBoot的cache)

  介绍:

在这里插入图片描述
在这里插入图片描述

  使用方式:

   @Cacheable注解:

在这里插入图片描述

   @CachePut注解:

在这里插入图片描述

   @CacheEvict注解:

在这里插入图片描述

   @CacheConfig注解:
// 一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用
@CacheConfig(cacheNames="emp") //抽取缓存的公共配置
   @Caching注解:

在这里插入图片描述

示例:

// 开启缓存
@EnableCaching
public class Springboot01CacheApplication {
 
  public static void main(String[] args) {
     SpringApplication.run(Springboot01CacheApplication.class, args);
  }
}
 // 其他方法使用和他一样, 具体可以看代码,来自己动动手试试看
 @Cacheable(cacheNames = {"emp"},condition = "#id>0")
        public Employee getEmp(Integer id){
            System.out.println("查询"+id+"号员工");
            Employee emp = employeeMapper.getEmpById(id);
            return emp;
        }

简易缓存工具类

 具体含义看代码注释

/**
 * @author huangye  所谓致知在格物者,言欲致吾之知,在即物而穷其理也。
 * @version 1.0  2020/10/4
 */
public class CacheUtil{

	private static  Cache<String, Object> cache;

	static {
		cache = createCache();
	}

	/**
	 * 插入缓存 | 更新缓存
	 * @param cacheName 缓存前缀
	 * @param key 键
	 * @param value 值
	 */
	public static void saveCache(String cacheName, String key, Object value) {
		System.out.printf("存储缓存的数据 key(%s) value(%s)",cacheName + "-" + key, value);
		System.out.println();
		cache.asMap().put(cacheName + "-" + key, value);
	}

	/**
	 * 根据键获取缓存
	 * @param cacheName 缓存前缀
	 * @param key 键
	 * @return Object类型, 由使用者自己转换
	 */
	public static Object getCache(String cacheName, String key) {
		System.out.printf("获取缓存的数据 key(%s) value(%s)",cacheName + "-" + key,
				cache.asMap().get(cacheName + "-" + key) );
		System.out.println();
		return cache.asMap().get(cacheName + "-" + key);
	}

	/**
	 * 根据键值删除缓存
	 * @param cacheName 缓存前缀
	 * @param key 建
	 */
	public static void deleteCache(String cacheName, String key) {
		System.out.printf("删除缓存的数据 key(%s)", cacheName + "-" + key);
		System.out.println();
		cache.asMap().remove(cacheName + "-" + key);
	}

	private static class CacheSingletonHolder {
		private final static Cache<String, Object> CACHE = Caffeine.newBuilder()
				// 初始的缓存空间大小
				.initialCapacity(100)
				// 缓存的最大条数
				.maximumSize(1000)
				// 最后一次缓存访问过后,7天后失效
				.expireAfterAccess(7, TimeUnit.DAYS)
				.build();
	}
	 private static Cache<String, Object> createCache() {
		return CacheSingletonHolder.CACHE;
	}
}

ps:这里的图片都来源于我学习时做的笔记(下图位证), 因为有的是在网上找文章学习的,所以可能会遇到有的是和别人一样的内容,我是想着吧那些之前看的文章放到文章末尾的,但是我找不到了非常抱歉, 我这里的话只是想做个知识的汇总,如果有错误的地方,可以评论留言 我会改正,谢谢
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Caffeine cache实现本地缓存(简单又清楚) 的相关文章

随机推荐

  • Access to from origin ‘null‘ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin‘ heade

    Access to XMLHttpRequest at span class token string 39 http localhost 8080 postgres mvt source 834 428 10 39 span from o
  • [实验一] 选择器

    该个栏目的博客都是基于南京大学的数字逻辑与计算机组成的课程设计 xff0c 方便以后进行总结归纳而准备的 这次实验是实验一 xff1a 选择器 设计一个简单的选择器 xff0c 介绍一些常用的多路选择器的设计方法 Verilog语言中的al
  • VMware虚拟机中安装的Linux系统无法识别U盘解决方法

    文章目录 1 问题描述2 解决方法3 参考文献 1 问题描述 如图1所示 xff0c 在VMware安装的Linux系统 xff08 Ubuntu 无法读取U盘 图 1 U盘读取失败 2 解决方法 原因在于所用的U盘为3 0接口 xff0c
  • 解决error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools"两个方法

    简述 在Windows下的pycharm安装出现 Microsoft Visual C 43 43 14 0 is required Get it with 34 Microsoft Visual C 43 43 Build Tools的解
  • ubuntu 18.04源码安装mysql 5.7.18

    一 安装依赖包 sudo apt update sudo apt install cmake bison libncurses5 dev build essential 二 下载 mysql 5 7 18源码 源码 传送门 选择那个包含bo
  • 什么叫做装箱和拆箱?一看就懂系列

    有很多同学对与装箱和拆箱还是有点搞不太明白 首先讲一下概念 xff1a 1 装箱指的是把值类型转化为引用类型 2 拆箱当然指的就是把引用类型转化为值类型 估计很多同学可能还分不清哪些是属于引用类型和值类型 这个就需要自己去强化记忆一下了 光
  • java 和javascript的区别?你是否还在把他们混为一谈呢

    1 javascript是基于对象的 xff0c 它是一种脚本语言 xff0c 是一种基于对象和事件驱动的编程语言 xff0c 因而它本身提供了非常丰富的内部对象供设计人员使用 而Java是面向对象的 xff0c 即Java是一种真正的面向
  • vs2019智能提示设置为中文

    官网修改中文提示地址 xff1a https docs microsoft com zh cn dotnet core install localized intellisense 1 去官网下载intellisense语言包 下载链接 x
  • .net中的定时任务

    FluentScheduler是什么 xff1f FluentScheduler是 net中的任务调度框架 xff0c 也就是你如果想在 net程序跑一段代码 xff0c 同时又不影响主程序的运行时 就可以使用FluentScheduler
  • 实用的Visual Studio插件

    打开Visual Studio 扩展 管理扩展 安装自己需要的插件 01 CodeMaid CodeMaid快速整理代码文件 xff0c 规范你的代码 xff0c 提高代码阅读体验 代码自动对齐 xff0c 格式化代码 xff08 ps x
  • mysql 数据库信息探索

    mysql 数据库信息探索 xff08 1 xff09 查询数据库的表数量 SELECT COUNT TABLES table schema FROM information schema TABLES GROUP BY table sch
  • .net 6 基于AspNetCoreRateLimit的限流

    1 安装包 AspNetCoreRateLimit 2 在appsetting cs中加入IpRateLimiting配置节点 span class token comment 限流配置 span span class token stri
  • 关于汉字转拼音并排序解决方案

    使用方法 xff1a 写一个静态帮助类 span class token keyword public span span class token keyword static span span class token keyword c
  • .NET Core6 中使用AutoMapper

    1 引入AutoMapper包 2 新建一个类 xff1a MappingProfile xff0c 类名自定义 xff0c 但是必须要继承 Profile类 用于创建映射规则 如图 xff1a Student为源数据 xff08 我这里是
  • 使用Python调用百度OCR

    使用Python调用百度OCR 注册 登录百度智能云创建应用安装python SDK接口说明代码实现 xff08 本地图片 xff09 代码实现 xff08 使用url上的图片并使用可选参数 xff09 注册 登录百度智能云 注册请点击 登
  • 001 超全C语言程序设计概念

    前言 此笔记主要参考自赵海英老师的C语言课程 xff0c 此笔记是在考研重新学习C语言的情况下进行的整理 xff0c 主要用于后续的C语言概念温故知新 第一章 基础知识 1 数制及转换 四种数制 xff1a 二进制 十进制 八进制 十六进制
  • 使用@Autowired注解警告Field injection is not recommended

    问题 xff1a 在使用变量方式依赖注入时 xff0c 提示Field injection is not recommended 64 Autowired LogService logService 虽然变量方式注入非常简洁 xff0c 但
  • mybatis动态数据源,分页插件失效

    mybatis动态数据源 xff0c 分页插件失效 发表于 xff1a 2020 08 18 20 42 47 阅读量 xff1a 9 作者 xff1a 黄叶 原因 xff1a 使用动态数据源 xff1a 数据正常但是total为0 解决
  • mybatis动态数据源配置使用事务不生效

    原因 xff1a 因为我使用的是配置的方式来加载数据源 xff0c 因此我们还需要对事务管理器进行一个配置 解决 xff1a 在代码中添加 配置事物 64 param dataSource 64 return 64 Bean public
  • Caffeine cache实现本地缓存(简单又清楚)

    Caffeine cache实现本地缓存题 缓存填充策略 手动加载 介绍 xff1a 使用方式 xff1a 同步加载 介绍 xff1a 使用方式 xff1a 异步加载 介绍 xff1a 注意 xff1a 异步和同步使用方式相似 这里的话主要