SpringBoot 使用 Caffeine 本地缓存

文章目录

          • 一、本地缓存介绍
          • 二、缓存组件 Caffeine 介绍
            • 2.1. Caffeine 性能
            • 2.2. Caffeine 配置说明
            • 2.3. 软引用与弱引用
          • 三、SpringBoot 集成 Caffeine 方式一
            • 3.1. Maven 引入相关依赖
            • 3.2. 配置缓存配置类
            • 3.3. 定义实体对象
            • 3.4. 定义服务接口类
            • 3.5. 定义服务接口实现类
            • 3.6. Caffeine工具类
            • 3.7. 测试案例
          • 四、测试案例
            • 4.1. 添加用户
            • 4.2. 查询用户
            • 4.3. 更新用户
            • 4.4. 删除用户
            • 4.5. 效果图
          • 五、第二种整合方式
            • 5.1. 依赖
            • 5.2. 接口实现类(替换)

一、本地缓存介绍

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。

之前介绍过 Redis 这种 NoSql 作为缓存组件,它能够很好的作为分布式缓存组件提供多个服务间的缓存,但是 Redis 这种还是需要网络开销,增加时耗。本地缓存是直接从本地内存中读取,没有网络开销,例如秒杀系统或者数据量小的缓存等,比远程缓存更合适。

二、缓存组件 Caffeine 介绍

按 Caffeine Github 文档描述,Caffeine 是基于 JAVA 8 的高性能缓存库。并且在 spring5 (springboot 2.x) 后,spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。

2.1. Caffeine 性能

可以通过下图观测到,在下面缓存组件中 Caffeine 性能是其中最好的。

在这里插入图片描述

2.2. Caffeine 配置说明

在这里插入图片描述
注意:

weakValues 和 softValues 不可以同时使用。
maximumSize 和 maximumWeight 不可以同时使用。
expireAfterWrite 和 expireAfterAccess 同事存在时,以 expireAfterWrite 为准。

2.3. 软引用与弱引用

软引用:如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。

弱引用:弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存.

// 软引用
Caffeine.newBuilder().softValues().build();// 弱引用
Caffeine.newBuilder().weakKeys().weakValues().build();
三、SpringBoot 集成 Caffeine 方式一
3.1. Maven 引入相关依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--字符串工具类--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
3.2. 配置缓存配置类
package com.gblfy.config;import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.concurrent.TimeUnit;/*** 本地caffeine缓存配置** @author gblfy* @date 2022-03-15*/
@Configuration
public class CaffeineCacheConfig {@Beanpublic Cache<String, Object> caffeineCache() {return Caffeine.newBuilder()// 设置最后一次写入或访问后经过固定时间过期.expireAfterWrite(6000, TimeUnit.SECONDS)// 初始的缓存空间大小.initialCapacity(100)// 缓存的最大条数.maximumSize(1000).build();}
}
3.3. 定义实体对象
package com.gblfy;import lombok.Data;
import lombok.ToString;@Data
@ToString
public class UserInfo {private Integer id;private String name;private String sex;private Integer age;
}
3.4. 定义服务接口类
package com.gblfy.service;import com.gblfy.entity.UserInfo;/*** 用户模块接口** @author gblfy* @date 2022-03-15*/
public interface UserInfoService {/*** 增加用户信息** @param userInfo 用户信息*/void addUserInfo(UserInfo userInfo);/*** 获取用户信息** @param id 用户ID* @return 用户信息*/UserInfo getByName(Integer id);/*** 修改用户信息** @param userInfo 用户信息* @return 用户信息*/UserInfo updateUserInfo(UserInfo userInfo);/*** 删除用户信息** @param id 用户ID*/void deleteById(Integer id);}
3.5. 定义服务接口实现类
package com.gblfy.service.impl;import com.gblfy.entity.UserInfo;
import com.gblfy.service.UserInfoService;
import com.gblfy.uitls.CaffeineUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 用户模块接口实现类** @author gblfy* @date 2022-03-15*/
@Slf4j
@Service
public class UserInfoServiceImpl implements UserInfoService {/*** 模拟数据库存储数据*/private Map<Integer, UserInfo> userInfoMap = new ConcurrentHashMap<>();@Autowiredprivate CaffeineUtils caffeineUtils;@Overridepublic void addUserInfo(UserInfo userInfo) {log.info("create");userInfoMap.put(userInfo.getId(), userInfo);// 加入缓存caffeineUtils.putAndUpdateCache(String.valueOf(userInfo.getId()), userInfo);}@Overridepublic UserInfo getByName(Integer userId) {// 先从缓存读取UserInfo userInfo = caffeineUtils.getObjCacheByKey(String.valueOf(userId), UserInfo.class);if (userInfo != null) {return userInfo;}// 如果缓存中不存在,则从库中查找log.info("get");userInfo = userInfoMap.get(userId);// 如果用户信息不为空,则加入缓存if (userInfo != null) {caffeineUtils.putAndUpdateCache(String.valueOf(userInfo.getId()), userInfo);}return userInfo;}@Overridepublic UserInfo updateUserInfo(UserInfo userInfo) {log.info("update");if (!userInfoMap.containsKey(userInfo.getId())) {return null;}// 取旧的值UserInfo oldUserInfo = userInfoMap.get(userInfo.getId());// 替换内容if (StringUtils.isNotBlank(oldUserInfo.getName())) {oldUserInfo.setName(userInfo.getName());}if (StringUtils.isNotBlank(oldUserInfo.getSex())) {oldUserInfo.setSex(userInfo.getSex());}oldUserInfo.setAge(userInfo.getAge());// 将新的对象存储,更新旧对象信息userInfoMap.put(oldUserInfo.getId(), oldUserInfo);// 替换缓存中的值caffeineUtils.putAndUpdateCache(String.valueOf(oldUserInfo.getId()), oldUserInfo);return oldUserInfo;}@Overridepublic void deleteById(Integer id) {log.info("delete");userInfoMap.remove(id);// 从缓存中删除caffeineUtils.removeCacheByKey(String.valueOf(id));}}
3.6. Caffeine工具类
package com.gblfy.uitls;import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** Caffeine缓存工具类** @Author gblfy* @Date 2022-03-15 14:58**/
@Component
public class CaffeineUtils {@AutowiredCache<String, Object> caffeineCache;/*** 添加或更新缓存** @param key* @param value*/public void putAndUpdateCache(String key, Object value) {caffeineCache.put(key, value);}/*** 获取对象缓存** @param key* @return*/public <T> T getObjCacheByKey(String key, Class<T> t) {caffeineCache.getIfPresent(key);return (T) caffeineCache.asMap().get(key);}/*** 根据key删除缓存** @param key*/public void removeCacheByKey(String key) {// 从缓存中删除caffeineCache.asMap().remove(key);}
}
3.7. 测试案例
package com.gblfy;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** 用户模块入口** @author gblfy* @date 2022-03-15*/
@RestController
@RequestMapping
public class UserInfoController {@Autowiredprivate UserInfoService userInfoService;@GetMapping("/userInfo/{id}")public Object getUserInfo(@PathVariable Integer id) {UserInfo userInfo = userInfoService.getByName(id);if (userInfo == null) {return "没有该用户";}return userInfo;}@PostMapping("/userInfo")public Object createUserInfo(@RequestBody UserInfo userInfo) {userInfoService.addUserInfo(userInfo);return "SUCCESS";}@PutMapping("/userInfo")public Object updateUserInfo(@RequestBody UserInfo userInfo) {UserInfo newUserInfo = userInfoService.updateUserInfo(userInfo);if (newUserInfo == null) {return "不存在该用户";}return newUserInfo;}@DeleteMapping("/userInfo/{id}")public Object deleteUserInfo(@PathVariable Integer id) {userInfoService.deleteById(id);return "SUCCESS";}}
四、测试案例
4.1. 添加用户
请求方式:POST
content-type:application/json
测试地址:localhost:8080/userInfo

报文内容

{'id':1,'name':"yx",'sex':"女",'age':2
}
4.2. 查询用户
请求方式:GET
测试地址:localhost:8080/userInfo/1
4.3. 更新用户
请求方式:PUT
content-type:application/json
测试地址:localhost:8080/userInfo

报文内容

{'id':1,'name':"gblfy",'sex':"男",'age':22
}
4.4. 删除用户
请求方式:DELETE
测试地址:localhost:8080/userInfo/1
4.5. 效果图

在这里插入图片描述

五、第二种整合方式
5.1. 依赖

上面基础上添加

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
5.2. 接口实现类(替换)
package com.gblfy;import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import java.util.HashMap;/*** 用户模块接口实现类** @author gblfy* @date 2022-03-15*/
@Slf4j
@Service
@CacheConfig(cacheNames = "caffeineCacheManager")
public class UserInfoServiceImpl implements UserInfoService {/*** 模拟数据库存储数据*/private HashMap<Integer, UserInfo> userInfoMap = new HashMap<>();@Override@CachePut(key = "#userInfo.id")public void addUserInfo(UserInfo userInfo) {log.info("create");userInfoMap.put(userInfo.getId(), userInfo);}@Override@Cacheable(key = "#id")public UserInfo getByName(Integer id) {log.info("get");return userInfoMap.get(id);}@Override@CachePut(key = "#userInfo.id")public UserInfo updateUserInfo(UserInfo userInfo) {log.info("update");if (!userInfoMap.containsKey(userInfo.getId())) {return null;}// 取旧的值UserInfo oldUserInfo = userInfoMap.get(userInfo.getId());// 替换内容if (!StringUtils.isEmpty(oldUserInfo.getAge())) {oldUserInfo.setAge(userInfo.getAge());}if (!StringUtils.isEmpty(oldUserInfo.getName())) {oldUserInfo.setName(userInfo.getName());}if (!StringUtils.isEmpty(oldUserInfo.getSex())) {oldUserInfo.setSex(userInfo.getSex());}// 将新的对象存储,更新旧对象信息userInfoMap.put(oldUserInfo.getId(), oldUserInfo);// 返回新对象信息return oldUserInfo;}@Override@CacheEvict(key = "#id")public void deleteById(Integer id) {log.info("delete");userInfoMap.remove(id);}}

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

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

相关文章

《Istio 从懵圈到熟练:二分之一活的微服务》

作者 | 声东 阿里云售后技术专家 <关注阿里巴巴云原生公众号&#xff0c;回复 排查 即可下载电子书> 《深入浅出 Kubernetes》一书共汇集 12 篇技术文章&#xff0c;帮助你一次搞懂 6 个核心原理&#xff0c;吃透基础理论&#xff0c;一次学会 6 个典型问题的华丽操作…

为了追求更快,CPU、内存、I/O都做了哪些努力?

来源 | 编程技术宇宙责编 | 晋兆雨头图 | 付费下载于视觉中国背景曾经&#xff0c;我面试的时候有两个最怕的。一怕问算法&#xff0c;二怕问高并发。算法这个&#xff0c;自从刷了不少LeetCode&#xff0c;发现还是有套路可循的&#xff0c;虽不敢说算法能力有多强&#xff0c…

神结合!一招玩转K8s和微服务治理

发布会传送门 进入直播间还有好礼等你拿&#xff01; EDAS产品免费试用&#xff1a;https://www.aliyun.com/activity/middleware/edaspromotiononmay 首届云原生编程挑战赛正式开战&#xff01;立即报名瓜分330000现金奖&#xff1a;https://tianchi.aliyun.com/specials/p…

精讲23种设计模式-基于装饰模式~设计多级缓存框架

文章目录一、装饰模式1. 回顾多级缓存基本概念2. 装饰模式基本的概念3. 装饰模式应用场景4. 装饰者模式定义5. 基于Map手写Jvm内置缓存二、手写一级与二级缓存2.1. redis工具类2.2. 实体类2.3. 接口2.4. 数据库脚本2.5. 测试案例2.6. 测试效果分享三、设计多级缓存框架3.1. 缓存…

阿里云EDAS 3.0重磅发布,无侵入构建云原生应用

发布会传送门 进入直播间还有好礼等你拿&#xff01; EDAS产品免费试用&#xff1a;https://www.aliyun.com/activity/middleware/edaspromotiononmay 首届云原生编程挑战赛正式开战&#xff01;立即报名瓜分330000现金奖&#xff1a;https://tianchi.aliyun.com/specials/p…

二维数组的偏移量

数组的偏移量&#xff1a; 数组空间起始位置的偏移值。 公式&#xff1a; 例题&#xff1a; 结合图片分析例题和公式&#xff1a;

Akamai “三驾马车”,如何应对疫情后新场景形态下的新考验?

2020年10月14日&#xff0c;CDN行业领头羊、负责提供安全数字化体验的智能边缘平台Akamai&#xff08;阿卡迈技术&#xff09;发布了其边缘计算、媒体交付和安全方面的产品组合的多项更新。其中在Akamai智能边缘&#xff08;Akamai Intelligent Edge&#xff09;、媒体交付、应…

如何使用MaxCompute Spark读写阿里云Hbase

背景 Spark on MaxCompute可以访问位于阿里云VPC内的实例&#xff08;例如ECS、HBase、RDS&#xff09;,默认MaxCompute底层网络和外网是隔离的&#xff0c;Spark on MaxCompute提供了一种方案通过配置spark.hadoop.odps.cupid.vpc.domain.list来访问阿里云的vpc网络环境的Hba…

elementui更改el-table表头背景颜色和字体颜色

博主在使用elementui中的el-table时感觉默认表格样式实在过于简洁&#xff0c;尤其表头与表格内容之间区别较小&#xff0c;不利于辨认&#xff0c;降低了用户体验。如图所示&#xff1a; 于是&#xff0c;博主尝试更改一下表头的背景颜色和字体颜色&#xff0c;方法如下&…

idea 提升幸福感 常用设置(重装机配置)

1.常用快捷键 alt 7 展示类的方法 CtrlH 查看当前所选类的继承关系 CtrlShift上下键 上下移动整行 2.自动导包&#xff1a; 3.自动创建 serialVersionUID IDEA 自动给实现了 Serializable 接口的类创建 serialVersionUID 4.类与方法注释快捷键设置 方法注释模板设置 类与方…

ClickHouse内核分析-MergeTree的Merge和Mutation机制

注&#xff1a;以下分析基于开源 v19.15.2.2-stable 版本进行 引言 ClickHouse内核分析系列文章&#xff0c;继上一篇文章 MergeTree查询链路 之后&#xff0c;这次我将为大家介绍MergeTree存储引擎的异步Merge和Mutation机制。建议读者先补充上一篇文章的基础知识&#xff0…

el-table中奇偶行背景色显示不同的颜色

默认样式 深色主题 border ref"singleTable" highlight-current-row current-change"handleCurrentChange" :row-class-name"tableRowClassName" :header-cell-style"{background:#004d8c,color:#FFFFFF}"事件方法 //奇偶行背景色不…

阿里云专属数据库,重新定义云数据库新形态

阿里云数据库专属集群专属链接 云专属数据库&#xff0c;重新定义云数据库新形态 数据库是一个有着超过40年历史的悠久行业&#xff0c;前期一直被传统的如Oracle等少数几家厂商把持。云计算的先行者AWS在2009年率先推出RDS服务&#xff08;Relational Database Service &…

软考零散知识点

网络命令 多态 强制多态&#xff1a;数字类型运算的自动拆装箱 过载多态&#xff1a;子类重写父类的方法 参数多态&#xff1a;方法的重载 包含多态&#xff1a;父类的引用指向子类的对象 主存和cache映射 RAID RAID RAID0&#xff1a;无冗余备份&#xff0c;带化。每条数据…

ServiceMesh最火项目:Istio架构解析

Istio 是一个开源的服务网格&#xff0c;可为分布式微服务架构提供所需的基础运行和管理要素。随着各组织越来越多地采用云平台&#xff0c;开发者必须使用微服务设计架构以实现可移植性&#xff0c;而运维人员必须管理包含混合云部署和多云部署的大型分布式应用。Istio 采用一…

docker-compose 实战案例

文章目录一、Compose入门案例1. 依赖2. 实体类3. mapper接口4. 启动类5. yml配置6. 测试案例7. 打包二、制作 DockerFile和docker-compose.yml2.1. 制作 DockerFile2.2. docker-compose.yml三、打包部署3.1. 资料上传3.2. 启动docker-compose3.3. 创建表3.4. 接口测试3.5. 数据…

F5打造“感知可控,随需而变的应用”  助力企业实现非凡数字体验

2020年12月16日&#xff0c;F5举办线上发布会&#xff0c;介绍其全新理念—“感知可控&#xff0c;随需而变的应用”(Adaptive Applications)&#xff0c;以及相应的创新性整体解决方案。在当前数字化转型加速的背景下&#xff0c;F5致力于为企业打造感知可控、随需应变的应用&…

软考 - 排序算法

文章目录1.总览1.待操作数组2.直接插入排序&#xff08;O(n2)&#xff09;3.希尔排序4.直接选择排序5.堆排序5.1.堆的分类5.2.原理&#xff1a;5.3. 堆排序方法&#xff1a;6.冒泡排序7.快速排序8.归并排序9.基数排序1.总览 1.待操作数组 private static int[] ori {30, 70, …

“数据湖”:概念、特征、架构与案例

写在前面&#xff1a; 最近&#xff0c;数据湖的概念非常热&#xff0c;许多前线的同学都在讨论数据湖应该怎么建&#xff1f;阿里云有没有成熟的数据湖解决方案&#xff1f;阿里云的数据湖解决方案到底有没有实际落地的案例&#xff1f;怎么理解数据湖&#xff1f;数据湖和大数…

DockerFile 入门到精通

文章目录一、DockerFile快速入门1. DockerFile 解析2. DockerFile编写规范3. DockerFile指令二、构建自己centos镜像2.1. 制作Dockerfile2.2. 构建镜像2.3. 运行容器一、DockerFile快速入门 1. DockerFile 解析 一个镜像文件到底是如何创建&#xff1f; dockerfile 描述出镜…