Caffeine缓存

2024-09-03

java

君子威而不猛,忿而不怒,忧而不惧,悦而不喜。——诸葛亮

  1. 项目介绍

Caffeine是一个基于Java8开发的提供了近乎最佳命中率的高性能的缓存库。

缓存和ConcurrentMap有点相似,但还是有所区别。最根本的区别是ConcurrentMap将会持有所有加入到缓存当中的元素,直到它们被从缓存当中手动移除。但是,Caffeine的缓存Cache 通常会被配置成自动驱逐缓存中元素,以限制其内存占用。在某些场景下,LoadingCacheAsyncLoadingCache 因为其自动加载缓存的能力将会变得非常实用。

Caffeine提供了灵活的构造器去创建一个拥有下列特性的缓存:

为了提高集成度,扩展模块提供了JSR-107 JCacheGuava适配器。JSR-107规范了基于Java 6的API,在牺牲了功能和性能的代价下使代码更加规范。Guava的Cache是Caffeine的原型库并且Caffeine提供了适配器以供简单的迁移策略。

  1. 官方文档、GitHub地址

上述链接提供了 Caffeine 的详细使用指南、API 参考和最佳实践,方便开发者快速上手和深入了解。

  1. 引入依赖

在项目中使用 Caffeine 非常简单,只需在构建工具中添加相应的依赖即可。

对于 Maven 用户:

1
2
3
4
5
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.8</version>
</dependency>

对于 Gradle 用户:

1
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'

注意: 请根据项目需求和兼容性选择合适的版本,最新版本可在 Maven Central 查询。

  1. 例子

下面展示一个简单的示例,演示如何使用 Caffeine 创建和使用缓存。

示例:用户信息缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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, User> userCache = Caffeine.newBuilder()
.maximumSize(1000) // 设置缓存最大容量
.expireAfterWrite(5, TimeUnit.MINUTES) // 设置写入后过期时间
.recordStats() // 启用统计功能
.build();

// 放入缓存
userCache.put("user123", new User("user123", "Alice"));

// 从缓存获取
User user = userCache.getIfPresent("user123");
System.out.println(user); // 输出:User{id='user123', name='Alice'}

// 使用加载函数获取,当缓存中不存在时自动加载
User user2 = userCache.get("user456", id -> fetchUserFromDatabase(id));
System.out.println(user2); // 输出:User{id='user456', name='Bob'}

// 查看缓存统计信息
System.out.println("Cache hit count: " + userCache.stats().hitCount());
System.out.println("Cache miss count: " + userCache.stats().missCount());
}

private static User fetchUserFromDatabase(String userId) {
System.out.println("Fetching user from database for id: " + userId);
return new User(userId, "Bob");
}

static class User {
private final String id;
private final String name;

public User(String id, String name) {
this.id = id;
this.name = name;
}

@Override
public String toString() {
return "User{id='" + id + "', name='" + name + "'}";
}
}
}

代码解析:

  1. 创建缓存实例:

    • 使用 Caffeine.newBuilder() 创建缓存构建器。
    • 设置 maximumSize(1000) 限制缓存最多存储 1000 个条目,超过后按照 LRU 策略淘汰。
    • 设置 expireAfterWrite(5, TimeUnit.MINUTES) 指定缓存项在写入 5 分钟后过期。
    • 启用 recordStats() 可以记录缓存的命中率等统计信息。
  2. 缓存操作:

    • 使用 put 方法将数据放入缓存。
    • 使用 getIfPresent 方法尝试从缓存获取数据,如果不存在则返回 null。
    • 使用 get 方法并提供加载函数,当缓存中不存在对应数据时会调用加载函数获取并存入缓存。
  3. 统计信息:

    • 通过 userCache.stats() 获取缓存的统计数据,包括命中次数、未命中次数等。

运行结果:

1
2
3
4
5
User{id='user123', name='Alice'}
Fetching user from database for id: user456
User{id='user456', name='Bob'}
Cache hit count: 1
Cache miss count: 1

实际应用中,Caffeine 可以帮助你:

  • 提高系统性能:减少对底层数据源(如数据库、远程服务)的访问次数,降低延迟。
  • 增强系统稳定性:在高并发场景下,通过缓存分担数据源压力,避免服务过载。
  • 简化代码维护:提供简洁统一的缓存操作接口,易于集成和扩展。

高级特性:

  • 异步缓存加载:使用 Caffeine.newBuilder().buildAsync() 创建异步缓存,适合 I/O 密集型操作。
  • 刷新策略:使用 refreshAfterWrite 设置缓存自动刷新,实现数据的实时性和一致性。
  • 监听器支持:可以注册监听器,在缓存数据被创建、更新或删除时执行特定操作。

参考文档:

总结:
Caffeine 提供了强大且灵活的缓存功能,是 Java 开发中不可或缺的性能优化工具。通过合理配置和使用,可以显著提升应用程序的响应速度和稳定性。

建议:
在引入 Caffeine 时,根据具体业务需求调整缓存策略,定期监控和分析缓存的性能指标,确保缓存系统始终高效运行。