文章目录

  • 一、本地缓存介绍
  • 二、缓存组件 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);}}

SpringBoot 使用 Caffeine 本地缓存相关推荐

  1. (很全面)SpringBoot 使用 Caffeine 本地缓存

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:超级小豆丁 http://www.mydlq.club/article/56/ 目录 ...

  2. caffeine本地缓存的使用和详解

    在项目中我们经常使用缓存架构,来缓存我们的数据,比如redis.caffeine等.那么redis和caffeine有什么区别?作用又有哪些不同呢? caffeine本地缓存的使用和详解 caffei ...

  3. SpringBoot + Caffeine本地缓存

    目录 SpringBoot + Caffeine配置 1.引入依赖 2.缓存常量CacheConstants 2.缓存枚举类CacheEnum 3.缓存配置类CacheConfig 4.项目中使用 5 ...

  4. SpringBoot 之 集成Caffeine本地缓存

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

  5. Caffeine本地缓存

    一.Caffine简介 简单说,Caffine 是一款高性能的本地缓存组件 由下面三幅图可见:不管在并发读.并发写还是并发读写的场景下,Caffeine 的性能都大幅领先于其他本地开源缓存组件 二.常 ...

  6. SpringBoot中使用本地缓存

    使用本地缓存的目的是加快数据读取速度,减少对数据库的访问,降低数据库压力.本地缓存是直接从本地内存中读取数据,没有网络开销.不同与Redis,Redis能够很好的作为分布式缓存组件提供多个服务间的缓存 ...

  7. 【Java】SpringBoot使用caffeine构建缓存带实例源码

    目录 一.什么是caffeine 二.SpringBoot整合caffeine 1. SpringBoot项目基础运行 2. 基于maven安装caffeine 3. 缓存注解说明 4. 实际代码 1 ...

  8. Caffeine本地缓存详解

    一. 概述 Caffeine是一种高性能的缓存库,是基于Java 8的最佳(最优)缓存框架. 基于Google的Guava Cache,Caffeine提供一个性能卓越的本地缓存(local cach ...

  9. Caffeine本地缓存详解(一篇就明白)

    结论:Caffeine 是目前性能最好的本地缓存,因此,在考虑使用本地缓存时,直接选择 Caffeine 即可. 先看一个小例子,明白如何创建一个 Caffeine 缓存实例. Caffeine ca ...

最新文章

  1. 北大高材生割美国韭菜被FBI通缉?本人回应予以否认
  2. 把字符串转换为日期时间
  3. 学术圈要炸锅:论文作者和审稿人串通欺骗盲审,ACM Fellow发文痛斥!顶会“想中就中”...
  4. POJ 2112 Optimal Milking(二分图匹配)
  5. 网络库urillib3
  6. SQL性能优化应该考虑哪些?
  7. sap-ui-core.js reference in Webclient ui
  8. mac 下 ~/.bash_profile无效
  9. 中小微企业税务数据的指标分析
  10. 如何在浏览器中显示本地文件系统_如何完全卸载浏览器中的Flash插件
  11. C++_public、private、protected权限介绍
  12. Python调shell
  13. 中级系统集成项目管理工程师考试记录之总述
  14. cdrx4自动排版步骤_coreldraw x4怎么排版 coreldraw书册杂志的排版方法 - 电脑常识 - 服务器之家...
  15. iPad的尺寸与分辨率
  16. 神舟笔记本风扇声音很大怎么办
  17. 移动方块java,技术编辑教你解决Java移动方块触碰边界反弹
  18. js统计字符串中大写字母与小写字母的总个数
  19. 英语口语练习三十二之英文口语中生病时该如何陈述症状
  20. 猜名次 C语言简单的实现

热门文章

  1. 大佬!莫言获颁第13个荣誉博士学位
  2. 清华“最强本科生”揭晓!网友:我大概是来凑数的……
  3. 现代数学和理论物理已经发展到多么令人震惊的水平了?
  4. avlib java_fatal error: libavutil/avconfig.h: No such file...
  5. mysql 第二天数据_MySQL入门第二天------数据库操作
  6. NS2相关学习——完成一个新协议(3)
  7. CMD命令之BAT脚本语法详解
  8. 二分查找 java代码实现
  9. 如何构建流量无损的在线应用架构 | 专题开篇
  10. 一个易用、易部署的Python遗传算法库