环境配置:

JDK 版本:1.8

Caffeine 版本:2.8.0

SpringBoot 版本:2.2.2.RELEASE

一、本地缓存介绍

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

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

二、缓存组件 Caffeine 介绍

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

1、Caffeine 性能

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

2、Caffeine 配置说明

参数

类型

描述

initialCapacity

integer

初始的缓存空间大小

maximumSize

long

缓存的最大条数

maximumWeight

long

缓存的最大权重

expireAfterAccess

duration

最后一次写入或访问后经过固定时间过期

refreshAfterWrite

duration

最后一次写入后经过固定时间过期

refreshAfterWrite

duration

创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存

weakKeys

boolean

打开 key 的弱引用

weakValues

boolean

打开 value 的弱引用

softValues

boolean

打开 value 的软引用

recordStats

-

开发统计功能

注意:

weakValues 和 softValues 不可以同时使用。

maximumSize 和 maximumWeight 不可以同时使用。

expireAfterWrite 和 expireAfterAccess 同事存在时,以 expireAfterWrite 为准。

3、软引用与弱引用

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

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

// 软引用

Caffeine.newBuilder().softValues().build();

// 弱引用

Caffeine.newBuilder().weakKeys().weakValues().build();

三、SpringBoot 集成 Caffeine 两种方式

SpringBoot 有俩种使用 Caffeine 作为缓存的方式:

方式一: 直接引入 Caffeine 依赖,然后使用 Caffeine 方法实现缓存。

方式二: 引入 Caffeine 和 Spring Cache 依赖,使用 SpringCache 注解方法实现缓存。

下面将介绍下,这俩中集成方式都是如何实现的。

Spring Boot 基础就不介绍了,推荐看下这个教程:

四、SpringBoot 集成 Caffeine 方式一

1、Maven 引入相关依赖

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.2.2.RELEASE

mydlq.club

springboot-caffeine-cache-example-1

0.0.1

springboot-caffeine-cache-example-1

Demo project for Spring Boot Cache

1.8

org.springframework.boot

spring-boot-starter-web

com.github.ben-manes.caffeine

caffeine

org.projectlombok

lombok

org.springframework.boot

spring-boot-maven-plugin

2、配置缓存配置类

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;

@Configuration

public class CacheConfig {

@Bean

public Cache caffeineCache() {

return Caffeine.newBuilder()

// 设置最后一次写入或访问后经过固定时间过期

.expireAfterWrite(60, TimeUnit.SECONDS)

// 初始的缓存空间大小

.initialCapacity(100)

// 缓存的最大条数

.maximumSize(1000)

.build();

}

}

3、定义测试的实体对象

import lombok.Data;

import lombok.ToString;

@Data

@ToString

public class UserInfo {

private Integer id;

private String name;

private String sex;

private Integer age;

}

4、定义服务接口类和实现类

UserInfoService

import mydlq.club.example.entity.UserInfo;

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);

}

UserInfoServiceImpl

import com.github.benmanes.caffeine.cache.Cache;

import lombok.extern.slf4j.Slf4j;

import mydlq.club.example.entity.UserInfo;

import mydlq.club.example.service.UserInfoService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.util.StringUtils;

import java.util.HashMap;

@Slf4j

@Service

public class UserInfoServiceImpl implements UserInfoService {

/**

* 模拟数据库存储数据

*/

private HashMap userInfoMap = new HashMap<>();

@Autowired

Cache caffeineCache;

@Override

public void addUserInfo(UserInfo userInfo) {

log.info("create");

userInfoMap.put(userInfo.getId(), userInfo);

// 加入缓存

caffeineCache.put(String.valueOf(userInfo.getId()),userInfo);

}

@Override

public UserInfo getByName(Integer id) {

// 先从缓存读取

caffeineCache.getIfPresent(id);

UserInfo userInfo = (UserInfo) caffeineCache.asMap().get(String.valueOf(id));

if (userInfo != null){

return userInfo;

}

// 如果缓存中不存在,则从库中查找

log.info("get");

userInfo = userInfoMap.get(id);

// 如果用户信息不为空,则加入缓存

if (userInfo != null){

caffeineCache.put(String.valueOf(userInfo.getId()),userInfo);

}

return userInfo;

}

@Override

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);

// 替换缓存中的值

caffeineCache.put(String.valueOf(oldUserInfo.getId()),oldUserInfo);

return oldUserInfo;

}

@Override

public void deleteById(Integer id) {

log.info("delete");

userInfoMap.remove(id);

// 从缓存中删除

caffeineCache.asMap().remove(String.valueOf(id));

}

}

5、测试的 Controller 类

import mydlq.club.example.entity.UserInfo;

import mydlq.club.example.service.UserInfoService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

@RestController

@RequestMapping

public class UserInfoController {

@Autowired

private 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";

}

}

五、SpringBoot 集成 Caffeine 方式二

1、Maven 引入相关依赖

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.2.2.RELEASE

mydlq.club

springboot-caffeine-cache-example-2

0.0.1

springboot-caffeine-cache-example-2

Demo project for Spring Boot caffeine

1.8

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-cache

com.github.ben-manes.caffeine

caffeine

org.projectlombok

lombok

org.springframework.boot

spring-boot-maven-plugin

2、配置缓存配置类

@Configuration

public class CacheConfig {

/**

* 配置缓存管理器

*

* @return 缓存管理器

*/

@Bean("caffeineCacheManager")

public CacheManager cacheManager() {

CaffeineCacheManager cacheManager = new CaffeineCacheManager();

cacheManager.setCaffeine(Caffeine.newBuilder()

// 设置最后一次写入或访问后经过固定时间过期

.expireAfterAccess(60, TimeUnit.SECONDS)

// 初始的缓存空间大小

.initialCapacity(100)

// 缓存的最大条数

.maximumSize(1000));

return cacheManager;

}

}

3、定义测试的实体对象

@Data

@ToString

public class UserInfo {

private Integer id;

private String name;

private String sex;

private Integer age;

}

4、定义服务接口类和实现类

服务接口

import mydlq.club.example.entity.UserInfo;

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);

}

服务实现类

import lombok.extern.slf4j.Slf4j;

import mydlq.club.example.entity.UserInfo;

import mydlq.club.example.service.UserInfoService;

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;

@Slf4j

@Service

@CacheConfig(cacheNames = "caffeineCacheManager")

public class UserInfoServiceImpl implements UserInfoService {

/**

* 模拟数据库存储数据

*/

private HashMap 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);

}

}

5、测试的 Controller 类

import mydlq.club.example.entity.UserInfo;

import mydlq.club.example.service.UserInfoService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

@RestController

@RequestMapping

public class UserInfoController {

@Autowired

private 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";

}

}

参考地址:

近期热文推荐:

觉得不错,别忘了随手点赞+转发哦!

黑帮2洛杉矶之王java_Spring Boot 2.x 把 Guava 干掉了,选择本地缓存之王 Caffeine!...相关推荐

  1. 本地缓存之王-Caffeine

    引言 随着业务体量的增长,使用的缓存方案一般会经过:1)无缓存直接查DB:2)数据同步+Redis:3)多级缓存 三个阶段. 第1阶段直接查DB只能用于小流量场景,随着QPS升高,需要引入缓存来减轻D ...

  2. 万字详解本地缓存之王 Caffeine

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来自:r6d.cn/UXR4 概要 Caffeine[1] ...

  3. Caffeine Cache~高性能 Java 本地缓存之王

    前面刚说到Guava Cache,他的优点是封装了get,put操作:提供线程安全的缓存操作:提供过期策略:提供回收策略:缓存监控.当缓存的数据超过最大值时,使用LRU算法替换.这一篇我们将要谈到一个 ...

  4. 3万字好文详解本地缓存之王 Caffeine

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 后台回复"大礼包"有惊喜礼包! 关注订阅号「程序员小乐」,收看更多精彩内容 每日英文 It has not ...

  5. 本地缓存之王——Caffeine 组件最强讲解!

    点击关注公众号,实用技术文章及时了解 结论:Caffeine 是目前性能最好的本地缓存,因此,在考虑使用本地缓存时,直接选择 Caffeine 即可. 先看一个小例子,明白如何创建一个 Caffein ...

  6. 据说是“缓存之王”? Caffeine高性能设计剖析

    概要 Caffeine[1]是一个高性能,高命中率,低内存占用,near optimal 的本地缓存,简单来说它是 Guava Cache 的优化加强版,有些文章把 Caffeine 称为" ...

  7. 玩转Spring Cache --- 整合进程缓存之王Caffeine Cache和Ehcache3.x【享学Spring】

    每篇一句 人到中年就是一部西游记:悟空的压力,八戒的身材,沙僧的发型,唐僧的唠叨 前言 前面文章大篇幅详细讲解了Spring Cache缓存抽象.三大缓存注解的工作原理等等.若是细心的小伙伴会发现:讲 ...

  8. Spring Boot 集成 本地缓存Guava框架

    Spring Boot 作为主流微服务框架,拥有成熟的社区生态.市场应用广泛,为了方便大家,整理了一个基于spring boot的常用中间件快速集成入门系列手册,涉及RPC.缓存.消息队列.分库分表. ...

  9. 真正的缓存之王,Google Guava 只是弟弟

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://blog.csdn.net/a953713428/article/details/92159746 前面刚说到 ...

最新文章

  1. CF650C Table Compression
  2. 第21届国际C语言混乱代码大赛获奖作品
  3. POJ1741 Tree 树中点对统计【树分治入门】
  4. ILMerge合并多个DLL
  5. 文件与流 -- fopen/fclose
  6. spark sql建表的异常
  7. python中threading模块中的Join类
  8. BGP中的联盟原理和实验(华为设备)
  9. LeaRun低代码平台快速开发工程项目管理软件
  10. MySQL 表空间碎片
  11. 借用传感器用计算机测速度题,图甲为利用距离传感器发出和接受超声波信号检测汽车速度的示意图.距离传感器发出的超声波遇到物......
  12. mysql中的left_MySQL left()函数
  13. 【支付宝小程序控制硬件①】 申请个人支付宝小程序开发的个人账户,说说那些睬坑日志,集成mqtt协议在支付宝小程序,实现基本通讯!
  14. 现在汉语也能编程了!学编程,英语还重要吗?
  15. WeChatDeveloper
  16. 7-9 部落 (25分)
  17. Docker 容器监控原理及 cAdvisor 的安装与使用
  18. C# Serializable [转]
  19. MySQL 与 Navicat for MySQL
  20. php百度热门关键词小偷,火端搜索2.1源码 PHP百度+好搜小偷程序

热门文章

  1. 《思维力:高效的系统思维》读书笔记01 - 思维力不足的4大痛点
  2. 实验六:555定时器
  3. 联想X86服务器重启管理控制器(XClarity Controller)或TSM的方法
  4. 外贸邮箱如何群发?163vip邮箱怎么收费?群发邮箱软件哪个好用?
  5. 2023年中职网络安全竞赛——CMS网站渗透解析
  6. 车站计算机联锁仿真设计,某折返站计算机联锁软件设计
  7. 将centos系统时间修改为上海时区(CST)
  8. Android - 实现导航栏的几种方式
  9. 从零开始读懂物理学:探索自然的奥秘
  10. fiddler的坑--手机无法安装fiddler证书