Caffeine是一个基于Java8的高性能,高命中率,低内存占用的缓存框架(near optimal 的本地缓存)具有较高的命中率和出色的并发能力,号称趋于完美。简单来说它是Guava Cache的优化加强版,Caffeine受启发于Guava Cache的API,使用API和Guava是一致的。它借鉴了Guava Cache和ConcurrentLinkedHashMap的设计经验。有些文章把Caffeine称为“新一代的缓存”、“现代缓存之王”。本文将重点讲解Caffeine的高性能设计,以及对应部分的源码分析。

性能比较

基准测试使用Java microbenchmark工具提供准确的分析。 缓存配置为

  • Caffeine和ConcurrentLinkedHashMap根据CPU数量确定其内部结构的大小
  • Guava的并发级别配置为64(默认为4,以减少内存使用)。
  • Ehcache v2在内部被硬编码为100个段,而v3未分段

100%的读操作

读75% 写25%

写100%

上面三种测试图来自于Caffeine官网,从图可知,Caffeine的性能玩爆其他缓存框架。

Springboot 集成 Caffeine 实战

在 Spring Boot 中集成也非常简单,提供了各种开箱既用的工具。

Caffeine 并不是分布式缓存.

Springboot 中引用的依赖

   <!-- springboot 缓存--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!-- caffeine 依赖--><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId></dependency>

配置文件

spring.cache.cache-names=cachename
spring.cache.caffeine.spec=initialCapacity=50,maximumSize=500,expireAfterWrite=5s
spring.cache.type=caffeine

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不可以同时使用

启动类中加入 @EnableCaching 注解 开启缓存

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication
//启用缓存
@EnableCaching
public class CaffeineDemoApplication {public static void main(String[] args) {SpringApplication.run(CaffeineDemoApplication.class, args);}}

创建 service, 其中有三个方法:

查询方法 cachecachename(), 获取需要缓存的数据, 调用 getCache() 方法

修改方法 cachePutcachename(), 更新缓存数据

getCache() 方法模拟生产项目中的逻辑代码, 线程睡眠 3s 模拟项目运行耗时

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;@Service
@Slf4j
public class CaffeineService {@Cacheable(value = "IZUUL", key = "#key")public String cacheIZUUL(String key) {log.info("cacheIZUUL()方法执行");return getCache(key);}@CachePut(value = "IZUUL", key = "#key")public String cachePutIZUUL(String key) {log.info("cachePutIZUUL()方法执行");return "cachePutIZUUL--" + key;}private String getCache(String key) {try {log.info("getCache()方法执行");Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return key;}
}

创建 controller 调用 service

package com.izuul.caffeinedemo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
public class CaffeineController {@Autowiredprivate CaffeineService caffeineService;@GetMapping("/cache-izuul/{key}")public String cacheIZUUL(@PathVariable String key) {return caffeineService.cacheIZUUL(key);}@GetMapping("/cache-put-izuul/{key}")public String cachePutIZUUL(@PathVariable String key) {return caffeineService.cachePutIZUUL(key);}}

以上配置过程比较死板, 没法实现多种缓存策略, 所以可以在项目中手动进行配置

删除 properties 文件中的配置

创建配置类 CaffeineConfig

import com.github.benmanes.caffeine.cache.Caffeine;
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 java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;@Configuration
public class CaffeineConfig {@Beanpublic CacheManager caffeineCacheManager() {SimpleCacheManager cacheManager = new SimpleCacheManager();List<CaffeineCache> caffeineCaches = new ArrayList<>();for (CacheType cacheType : CacheType.values()) {caffeineCaches.add(new CaffeineCache(cacheType.name(),Caffeine.newBuilder().expireAfterWrite(cacheType.getExpires(), TimeUnit.SECONDS).build()));}cacheManager.setCaches(caffeineCaches);return cacheManager;}
}

创建枚举类, 加入过期时间expires, 分别设置cachename消亡时间是 10s, MUMU 消亡时间 5s

public enum CacheType {IZUUL(10),MUMU(5);private int expires;CacheType(int expires) {this.expires = expires;}public int getExpires() {return expires;}
}

以上配置就完成了 在 service 中新增两个方法来进行验证

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;@Service
@Slf4j
public class CaffeineService {@Cacheable(value = "IZUUL", key = "#key")public String cacheIZUUL(String key) {log.info("cacheIZUUL()方法执行");return getCache(key);}@CachePut(value = "IZUUL", key = "#key")public String cachePutIZUUL(String key) {log.info("cachePutIZUUL()方法执行");return "cachePutIZUUL--" + key;}@Cacheable(value = "MUMU", key = "#key")public String cacheMUMU(String key) {log.info("cacheMUMU()方法执行");return getCache(key);}@CachePut(value = "MUMU", key = "#key")public String cachePutMUMU(String key) {log.info("cachePutMUMU()方法执行");return "cachePutMUMU--" + key;}private String getCache(String key) {try {log.info("getCache()方法执行");Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return key;}
}

controller 中调用新增的方法

package com.cachename.caffeinedemo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
public class CaffeineController {@Autowiredprivate CaffeineService caffeineService;@GetMapping("/cache/{key}")public String cachecachename(@PathVariable String key) {return caffeineService.cachecachename(key);}@GetMapping("/cache-put-cachename/{key}")public String cachePutcachename(@PathVariable String key) {return caffeineService.cachePutcachename(key);}@GetMapping("/cache-mumu/{key}")public String cacheMUMU(@PathVariable String key) {return caffeineService.cacheMUMU(key);}@GetMapping("/cache-put-mumu/{key}")public String cachePutMUMU(@PathVariable String key) {return caffeineService.cachePutMUMU(key);}
}

添加完成后 启动项目, 分别访问 http://localhost:8080/cache/cachename 和 http://localhost:8080/cache-mumu/mumu

你会发现 cahce-cachename 经过 10s 后会再一次执行 getCache() 方法, 说明它的缓存有 10s

而 cahce-mumu 是 5s

以上证明我们手动配置的 Caffeine 缓存策略成功了

在 java 项目中可以使用此方法进行本地缓存

[Springboot实战] 集成 Caffeine相关推荐

  1. SpringBoot 之 集成Caffeine本地缓存

    Caffeine的 github地址 使用版本说明: For Java 11 or above, use 3.0.x otherwise use 2.9.x SpringBoot 有两种使用 Caff ...

  2. Springboot/Cloud集成Sentinel 和 入门实战

    文章目录 一.Springboot/Cloud集成Sentinel 1. spring-cloud-alibaba依赖 2. 引入 Sentinel starter 3. 配置application. ...

  3. SpringBoot实战(十二):集成 Spring Boot Admin 监控

    强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 程序开发完实现相应的功能只是一个部分,如何让系统在线上运行更好创造更高的价值是另外一个 ...

  4. SpringBoot 集成 Caffeine(咖啡因)最优秀的本地缓存

    SpringBoot 集成 Caffeine(咖啡因)最优秀的本地缓存 本地缓存 为什么用Caffeine做本地缓存 SpringBoot2.0+如何集成 Caffeine 引入依赖 开启缓存 容器配 ...

  5. springboot实战pdf_Java程序员中秋节福利发送:Spring boot+Redis实战文档「PDF」

    中秋节越来越近了,平日里,各大公司拼员工拼技术拼实力:到了节日,则要拼奖金.拼福利.拼假期,还要拼创意.今天,小编为大家也准备了一份中秋节礼物,让我们一起来看看礼物是啥吧! Spring boot文档 ...

  6. SpringBoot实战(十三):Spring Boot Admin 动态修改日志级别

    强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 之前关于线上输出日志一直有个困惑:如何可以动态调整的日志级别,来保证系统在正常运行时性 ...

  7. springboot springmvc mybatis_深圳嘉华学校之springboot实战教程

    Springboot实战教程 目录 第一章 springBoot概述... 2 href="https://zhuanlan.zhihu.com/write#_Toc508178432&qu ...

  8. MyBatis系列之--Java 项目(非SpringBoot)集成MyBatis

    MyBatis系列之--Java 项目(非SpringBoot)集成MyBatis 对MyBatis简单介绍 核心接口SqlSessionFactory 实战 1. Maven创建Java项目 2. ...

  9. SpringBoot 快速集成 JWT 实现用户登录认证

    前言:当今前后端分离时代,基于Token的会话保持机制比传统的Session/Cookie机制更加方便,下面我会介绍SpringBoot快速集成JWT库java-jwt以完成用户登录认证. 一.JWT ...

最新文章

  1. 用无人机打点作画,密集恐惧症患者慎入!
  2. LeetCode --Search Insert Position
  3. 小菜鸟学 Spring-Dependency injection(二)
  4. 掌握这些 Redis 技巧,百亿数据量不在话下!
  5. LeetCode—1290.二进制链表转整数(Java)
  6. 中序遍历的模板(以及变形更新中。。。)
  7. 13.Git分支-变基(rebase)、rebase VS merge
  8. hibernate 继承_Hibernate继承:每个类层次结构的表
  9. 前端笔记-freemarker模板获取后端数据及提交数据
  10. 已经连接到空闲例程的解决方法
  11. Day2 - Python基础2作业【购物车程序】
  12. 杜甫的《望岳》在哪里作的?山脚下还是山头上?
  13. python架构师工作职责_软件架构师工作的职责
  14. MySQL查询某天(内)的数据
  15. Win10下IE无法打开网页的解决办法
  16. python sklearn逻辑回归 sgd和lr_LR逻辑回归模型的原理、公式推导、Python实现和应用...
  17. 精益看板方法从理论到实战 (6)—— 控制在制品数量(中)
  18. 我的世界服务器等级系统,[娱乐][角色][聊天][上古之石]LevelSignPlus——服务器等级声望系统[1.7.2-1.10.2]...
  19. 与日俱进,在 Go 1.20 中这种高效转换的方式又变了
  20. Go、Rust、C++和Zig语言的生产力对比 | Gopher Daily (2021.03.28) ʕ◔ϖ◔ʔ

热门文章

  1. R语言使用ggplot2包使用geom_dotplot函数绘制分组点图(添加均值、标准偏差)实战(dot plot)
  2. R语言as.name函数(转化为命名的类别对象)和is.name函数(检验是否是命名的类别对象)实战
  3. “package ‘ElemStatLearn‘ is not available for this version of R
  4. R假设检验之Jarque-Bera检验(Jarque-Bera Test)
  5. 贝叶斯岭回归(BayesianRidge)、自动关联决策回归、高斯过程、核函数、及高斯回归、高斯过程分类
  6. 奇异值分解SVD和偏最小二乘奇异值分解PLSSVD
  7. celldex包使用
  8. 白话——胡说图像分类器
  9. [Google API](2)什么是google API
  10. [Google API](1)简介