[Springboot实战] 集成 Caffeine
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相关推荐
- SpringBoot 之 集成Caffeine本地缓存
Caffeine的 github地址 使用版本说明: For Java 11 or above, use 3.0.x otherwise use 2.9.x SpringBoot 有两种使用 Caff ...
- Springboot/Cloud集成Sentinel 和 入门实战
文章目录 一.Springboot/Cloud集成Sentinel 1. spring-cloud-alibaba依赖 2. 引入 Sentinel starter 3. 配置application. ...
- SpringBoot实战(十二):集成 Spring Boot Admin 监控
强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 程序开发完实现相应的功能只是一个部分,如何让系统在线上运行更好创造更高的价值是另外一个 ...
- SpringBoot 集成 Caffeine(咖啡因)最优秀的本地缓存
SpringBoot 集成 Caffeine(咖啡因)最优秀的本地缓存 本地缓存 为什么用Caffeine做本地缓存 SpringBoot2.0+如何集成 Caffeine 引入依赖 开启缓存 容器配 ...
- springboot实战pdf_Java程序员中秋节福利发送:Spring boot+Redis实战文档「PDF」
中秋节越来越近了,平日里,各大公司拼员工拼技术拼实力:到了节日,则要拼奖金.拼福利.拼假期,还要拼创意.今天,小编为大家也准备了一份中秋节礼物,让我们一起来看看礼物是啥吧! Spring boot文档 ...
- SpringBoot实战(十三):Spring Boot Admin 动态修改日志级别
强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 之前关于线上输出日志一直有个困惑:如何可以动态调整的日志级别,来保证系统在正常运行时性 ...
- springboot springmvc mybatis_深圳嘉华学校之springboot实战教程
Springboot实战教程 目录 第一章 springBoot概述... 2 href="https://zhuanlan.zhihu.com/write#_Toc508178432&qu ...
- MyBatis系列之--Java 项目(非SpringBoot)集成MyBatis
MyBatis系列之--Java 项目(非SpringBoot)集成MyBatis 对MyBatis简单介绍 核心接口SqlSessionFactory 实战 1. Maven创建Java项目 2. ...
- SpringBoot 快速集成 JWT 实现用户登录认证
前言:当今前后端分离时代,基于Token的会话保持机制比传统的Session/Cookie机制更加方便,下面我会介绍SpringBoot快速集成JWT库java-jwt以完成用户登录认证. 一.JWT ...
最新文章
- 用无人机打点作画,密集恐惧症患者慎入!
- LeetCode --Search Insert Position
- 小菜鸟学 Spring-Dependency injection(二)
- 掌握这些 Redis 技巧,百亿数据量不在话下!
- LeetCode—1290.二进制链表转整数(Java)
- 中序遍历的模板(以及变形更新中。。。)
- 13.Git分支-变基(rebase)、rebase VS merge
- hibernate 继承_Hibernate继承:每个类层次结构的表
- 前端笔记-freemarker模板获取后端数据及提交数据
- 已经连接到空闲例程的解决方法
- Day2 - Python基础2作业【购物车程序】
- 杜甫的《望岳》在哪里作的?山脚下还是山头上?
- python架构师工作职责_软件架构师工作的职责
- MySQL查询某天(内)的数据
- Win10下IE无法打开网页的解决办法
- python sklearn逻辑回归 sgd和lr_LR逻辑回归模型的原理、公式推导、Python实现和应用...
- 精益看板方法从理论到实战 (6)—— 控制在制品数量(中)
- 我的世界服务器等级系统,[娱乐][角色][聊天][上古之石]LevelSignPlus——服务器等级声望系统[1.7.2-1.10.2]...
- 与日俱进,在 Go 1.20 中这种高效转换的方式又变了
- Go、Rust、C++和Zig语言的生产力对比 | Gopher Daily (2021.03.28) ʕ◔ϖ◔ʔ
热门文章
- R语言使用ggplot2包使用geom_dotplot函数绘制分组点图(添加均值、标准偏差)实战(dot plot)
- R语言as.name函数(转化为命名的类别对象)和is.name函数(检验是否是命名的类别对象)实战
- “package ‘ElemStatLearn‘ is not available for this version of R
- R假设检验之Jarque-Bera检验(Jarque-Bera Test)
- 贝叶斯岭回归(BayesianRidge)、自动关联决策回归、高斯过程、核函数、及高斯回归、高斯过程分类
- 奇异值分解SVD和偏最小二乘奇异值分解PLSSVD
- celldex包使用
- 白话——胡说图像分类器
- [Google API](2)什么是google API
- [Google API](1)简介