目录
Caffeine%EF%BC%9F-toc" style="margin-left:0px;">一.什么是Caffeine?
使用场景:
Caffeine%EF%BC%9F-toc" style="margin-left:0px;"> 二.如何使用Caffeine?
1.导入依赖:
2.在java项目中使用:
三.对缓存项的驱逐:
1.容量驱逐(Maximum Size):
2.过期驱逐(Expire After Write / Access):
3.驱逐指定缓存项(主动驱逐):
(1)使用 invalidate 方法驱逐指定缓存项:
(2)使用 invalidateAll 方法驱逐所有缓存项:
(3)使用 invalidate 方法并批量驱逐多个缓存项:
(4)使用 invalidate 方法与条件驱逐:
4.驱逐回调(Eviction Listener):
(1)注册驱逐监听器:
(2)缓存项因过期被驱逐时执行回调:
Caffeine%20%E4%BD%9C%E4%B8%BA%E7%BC%93%E5%AD%98%EF%BC%9A-toc" style="margin-left:0px;">四.在 Spring Boot 项目中使用 Caffeine 作为缓存:
Caffeine%20%E4%BE%9D%E8%B5%96%EF%BC%9A-toc" style="margin-left:40px;">1.添加 Caffeine 依赖:
2.创建配置类:
3.在 Controller 层注入 Cache 实例:
Caffeine%E4%B8%8ERedis%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9A-toc" style="margin-left:0px;">五.Caffeine与Redis的区别:
Caffeine%EF%BC%8C%E4%BD%95%E6%97%B6%E4%BD%BF%E7%94%A8%20Redis%EF%BC%9F-toc" style="margin-left:40px;">何时使用 Caffeine,何时使用 Redis?
Caffeine%EF%BC%9F">一.什么是Caffeine?
Caffeine 是一个高性能的 Java 缓存库,它被设计用于提供快速、可靠的缓存服务。它基于 Google Guava 的缓存系统,但进行了许多优化,旨在提升性能、减少内存消耗,并为缓存提供更多的灵活性。Caffeine 的设计目标是创建一个高效、低延迟的内存缓存系统,能够在高并发的场景下提供卓越的表现。
Caffeine 通过优化缓存的存储和访问机制,在 CPU 缓存和垃圾回收方面做了大量改进,从而能够在高并发下实现高效的缓存管理。
Caffeine 是一个 本地缓存,它的缓存存储在应用服务器的内存中。每个实例都有自己的缓存空间,因此缓存是 本地的,仅对当前的应用实例可见。如果我们有多个应用实例或多个服务,Caffeine 缓存不会自动共享,它的作用范围限制在当前的应用进程中。这种缓存通常用于加速对本地应用数据的访问,减少对数据库的频繁查询。
使用场景:
Caffeine%EF%BC%9F"> 二.如何使用Caffeine?
1.导入依赖:
<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1.0</version>
</dependency>
2.在java项目中使用:
Caffeine 提供了丰富的 API 来创建和管理缓存,下面是一个简单的示例。
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;import java.util.concurrent.TimeUnit;public class CaffeineExample {public static void main(String[] args) {// 创建一个缓存实例Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后10分钟过期.maximumSize(100) // 设置最大缓存条目数.build();// 存入缓存cache.put("key1", "value1");cache.put("key2", "value2");// 获取缓存String value = cache.getIfPresent("key1"); // 返回value1System.out.println("Cached value for key1: " + value);// 如果缓存中没有数据,使用一个加载函数填充缓存String loadedValue = cache.get("key3", key -> "loadedValue");System.out.println("Loaded value for key3: " + loadedValue);}
}
三.对缓存项的驱逐:
在 Caffeine 缓存中,驱逐(Eviction)指的是当缓存达到一定容量限制或过期时,自动移除缓存项的过程。Caffeine 提供了多种方式来控制缓存项的驱逐,包括基于缓存容量限制、缓存过期时间以及自定义驱逐策略。
Caffeine 提供了以下几种常见的驱逐策略:
1.容量驱逐(Maximum Size):
通过设置最大缓存容量,Caffeine 会根据缓存的容量进行驱逐,移除不常用的缓存项(通常是 LRU 策略,即最少使用的项会先被移除)。
Cache<String, String> cache = Caffeine.newBuilder().maximumSize(100) // 设置最大缓存容量为100.build();
当缓存的条目数超过最大容量时,Caffeine 会自动驱逐最少使用的条目。
2.过期驱逐(Expire After Write / Access):
Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟失效.expireAfterAccess(5, TimeUnit.MINUTES) // 访问后5分钟失效.maximumSize(100).build();
当缓存项超过指定的过期时间后,Caffeine 会自动移除这些缓存项。
3.驱逐指定缓存项(主动驱逐):
Caffeine 允许在运行时主动驱逐缓存中的某个指定项。这对于一些特殊情况非常有用,比如在缓存项的数据发生变化时,主动移除某个缓存项。
(1)使用 invalidate
方法驱逐指定缓存项:
我们可以使用 invalidate
方法来驱逐指定的缓存项。如果需要移除一个特定的缓存项,可以直接传入键名。
cache.invalidate("key1"); // 移除指定的缓存项
(2)使用 invalidateAll
方法驱逐所有缓存项:
如果需要清空缓存中的所有项,可以使用 invalidateAll
方法。
cache.invalidateAll(); // 移除所有缓存项
(3)使用 invalidate
方法并批量驱逐多个缓存项:
cache.invalidate("key1", "key2", "key3"); // 移除多个指定的缓存项
(4)使用 invalidate
方法与条件驱逐:
我们还可以根据特定条件来选择性地驱逐缓存项。例如,您可以实现一个条件判断逻辑来决定是否驱逐某个缓存项。
cache.invalidateIf((key, value) -> key.startsWith("prefix")); // 根据条件驱逐缓存项
4.驱逐回调(Eviction Listener):
Caffeine 提供了一个强大的驱逐监听器功能,允许在缓存项被驱逐时执行回调。这个功能对于缓存管理非常有用,特别是需要记录缓存被移除的原因,或者需要清理与缓存相关的资源。
(1)注册驱逐监听器:
我们可以使用 removalListener
方法来注册一个驱逐监听器。当缓存项被移除时,监听器会被触发。
Cache<String, String> cache = Caffeine.newBuilder().maximumSize(100).removalListener((key, value, cause) -> {System.out.println("Removed key: " + key + ", cause: " + cause);}).build();
回调参数说明:
驱逐的原因(
cause
)可以是以下几种:
(2)缓存项因过期被驱逐时执行回调:
Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).removalListener((key, value, cause) -> {if (cause == RemovalCause.EXPIRED) {System.out.println("Cache item expired: " + key);}}).build();
Caffeine 缓存提供了灵活且强大的驱逐机制,允许开发者根据不同的需求进行缓存项的移除和清理。常见的驱逐方式包括基于容量的驱逐、过期时间的驱逐、主动驱逐以及驱逐监听器。
Caffeine%20%E4%BD%9C%E4%B8%BA%E7%BC%93%E5%AD%98%EF%BC%9A">四.在 Spring Boot 项目中使用 Caffeine 作为缓存:
假设我们正在开发一个 Spring Boot 项目,其中包含一个频繁查询数据库的 UserService
,为了提升性能,我们决定在缓存中存储用户信息。对于某些高频率访问的数据(如用户基本信息),使用内存缓存可以显著提高响应速度。为了避免频繁地访问数据库,我们使用 Caffeine 来缓存用户数据。
Caffeine%20%E4%BE%9D%E8%B5%96%EF%BC%9A">1.添加 Caffeine 依赖:
在 pom.xml
中添加 Caffeine 依赖:
<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1.0</version>
</dependency>
2.创建配置类:
package cn.mybatisplus.redis_mq.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;@Configuration
public class CaffeineConfig {@Beanpublic Cache<Long,Object> ObjectCache(){return Caffeine.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES) // 5 分钟后过期.refreshAfterWrite(10, TimeUnit.MINUTES) // 每10分钟自动刷新缓存.maximumSize(100).build();}
}
3.在 Controller 层注入 Cache
实例:
在 Controller
中,使用 @Autowired
注解将 Cache<Long, Object>
缓存实例注入进来,直接使用缓存进行操作。
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/products")
public class ProductsController {@Autowiredprivate Cache<Long, Object> objectCache;// 模拟一个从缓存中获取数据的接口@GetMapping("/getUserInfo")public String getUserInfo(@RequestParam Long userId) {// 检查缓存中是否存在该用户数据Object cachedData = objectCache.getIfPresent(userId);if (cachedData != null) {return "Cache hit: " + cachedData;} else {// 模拟从数据库获取用户数据String userInfo = "User Info for " + userId;// 将查询到的数据放入缓存中objectCache.put(userId, userInfo);// 当缓存中没有对应 key 的数据时,它会被调用来加载数据并将结果存入缓存。objectCache.get(userId,key -> orderService.createOrder(key));return "Cache miss: " + userInfo;}}
}
如果希望在缓存失效或需要手动控制缓存刷新时使用更多功能,Caffeine
提供了丰富的 API,可以在代码中进行进一步的定制。例如:
objectCache.invalidate(userId); // 删除缓存
objectCache.refresh(userId); // 刷新缓存
Caffeine%E4%B8%8ERedis%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9A">五.Caffeine与Redis的区别:
Caffeine 和 Redis 都是常见的缓存解决方案,但它们各自有不同的优势和适用场景:
特性 | Caffeine | Redis |
---|---|---|
存储类型 | 内存缓存 | 分布式缓存(存储在外部内存中,如内存、磁盘等) |
性能 | 本地内存缓存,速度非常快,低延迟 | 由于需要网络请求,相较于 Caffeine 较慢 |
适用范围 | 单机应用,内存容量较小的缓存,低延迟缓存访问 | 分布式系统,跨机器的缓存,支持持久化存储 |
缓存容量 | 受限于 JVM 内存(可配置最大容量) | 可配置持久化存储,容量几乎无限 |
缓存失效策略 | 支持过期时间、LRU/LFU 淘汰策略 | 支持过期时间、LRU、LRU + 分布式缓存持久化策略 |
持久化支持 | 不支持持久化,只在 JVM 中缓存 | 支持持久化(内存、磁盘、备份等) |
分布式支持 | 仅适用于单机应用 | 支持分布式缓存,多个节点可以共享缓存 |
内存使用 | 内存缓存,适合小规模、高性能访问 | 内存/磁盘结合,适合大规模、高可用的分布式缓存 |
Caffeine%EF%BC%8C%E4%BD%95%E6%97%B6%E4%BD%BF%E7%94%A8%20Redis%EF%BC%9F">何时使用 Caffeine,何时使用 Redis?
①使用 Caffeine:如果你的应用只需要单机缓存,数据量相对较小,且要求极低的延迟(例如,数据库查询、网页请求缓存),Caffeine 是一个很好的选择。
场景:
②使用 Redis:如果你需要跨多个应用共享缓存,或者需要缓存的数据需要持久化,或者系统是分布式的,Redis 是更适合的选择。
场景:
在实际项目中,我们可以根据业务需求选择合适的缓存解决方案,甚至结合 Caffeine 和 Redis 使用,例如使用 Caffeine 缓存本地数据,使用 Redis 缓存跨应用的数据。