初识Caffeine

一、前言:为什么你需要 Caffeine?

你是否遇到过这些问题?

  • ❌ 频繁查询数据库,接口响应慢
  • ❌ 热点数据反复被请求,浪费资源
  • ❌ 手写 ConcurrentHashMap 缓存,结果内存爆炸(OOM)

Caffeine 是一个高性能、易用、现代化的 Java 本地缓存库 ,由 Guava Cache 的原作者打造,号称 "Guava Cache 的继任者"。

它能帮你:

微秒级数据访问 (比 Redis 快 1000 倍)

自动淘汰旧数据 ,防止内存溢出

一行代码实现缓存加载

本文将带你从零开始,快速上手 Caffeine!


二、Caffeine 是什么?

Caffeine 是一个基于 Java 8+ 的高性能进程内缓存库,特点如下:

特性 说明
高性能 采用 Window TinyLFU 淘汰算法,命中率更高
简单易用 API 与 Guava Cache 高度相似,学习成本低
功能丰富 支持自动过期、异步加载、统计监控等
社区活跃 Spring Boot 3.x 官方推荐本地缓存方案

💡 一句话理解 :Caffeine = 更快 + 更省内存 + 更智能 的 ConcurrentHashMap


三、快速入门:5 分钟上手 Caffeine

3.1 添加 Maven 依赖

XML 复制代码
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactityId>caffeine</artifactId>
    <version>3.1.8</version> <!-- 推荐使用最新版 -->
</dependency>

3.2 基础用法:手动存取

java 复制代码
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

public class CaffeineDemo {
    public static void main(String[] args) {
        // 创建缓存:最多存 1000 个条目,写入 5 分钟后过期
        Cache<String, String> cache = Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .build();

        // 存入数据
        cache.put("name", "Alice");

        // 读取数据
        String name = cache.getIfPresent("name");
        System.out.println(name); // 输出:Alice

        // 不存在时返回 null
        String notExist = cache.getIfPresent("age");
        System.out.println(notExist); // 输出:null
    }
}

四、高级用法:自动加载缓存(LoadingCache)

最强大的功能来了!当缓存未命中时,自动从数据源加载

4.1 自动回源查询数据库

java 复制代码
LoadingCache<Long, User> userCache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build(key -> {
        // 模拟从数据库加载
        System.out.println("从数据库加载用户: " + key);
        return loadUserFromDB(key); // 你的 DAO 方法
    });

// 第一次调用:触发 loadUserFromDB
User user1 = userCache.get(1001L);

// 第二次调用:直接从缓存返回
User user2 = userCache.get(1001L);

效果:业务代码无需关心"先查缓存再查 DB"的逻辑,Caffeine 自动搞定!


五、核心配置详解

5.1 淘汰策略

配置 作用
.maximumSize(1000) 最多缓存 1000 个 key-value
.expireAfterWrite(5, MINUTES) 写入后 5 分钟过期
.expireAfterAccess(10, MINUTES) 最后访问后 10 分钟过期
.weakKeys() key 使用弱引用(GC 可回收)
.softValues() value 使用软引用(内存不足时回收)

⚠️ 注意maximumSizeweak/soft 不能同时使用。

5.2 异步加载(AsyncLoadingCache)

java 复制代码
AsyncLoadingCache<String, String> asyncCache = Caffeine.newBuilder()
    .buildAsync((key, executor) -> 
        CompletableFuture.supplyAsync(() -> fetchDataFromRemote(key))
    );

CompletableFuture<String> future = asyncCache.get("data");
String result = future.get(); // 阻塞等待结果

六、监控缓存性能

Caffeine 内置统计功能,轻松查看命中率:

java 复制代码
Cache<String, Object> cache = Caffeine.newBuilder()
    .recordStats() // 开启统计
    .build();

// ... 使用缓存 ...

CacheStats stats = cache.stats();
System.out.println("命中率: " + stats.hitRate());     // 如 0.92
System.out.println("加载次数: " + stats.loadCount()); // 数据源调用次数

📊 生产建议:将命中率接入 Prometheus + Grafana,实时监控缓存健康度。


七、Caffeine vs Guava Cache

对比项 Guava Cache Caffeine
性能 一般 更高(TinyLFU 算法)
内存占用 较高 更低
功能 基础 更丰富(异步、权重等)
维护状态 停滞 活跃更新
Spring 支持 需手动集成 Spring Boot 3.x 官方支持

结论新项目请直接使用 Caffeine


八、在 Spring Boot 中使用 Caffeine

8.1 配置 Bean

java 复制代码
@Configuration
public class CacheConfig {

    @Bean
    public Cache<String, User> userCache() {
        return Caffeine.newBuilder()
            .maximumSize(5000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();
    }
}

8.2 在 Service 中注入使用

java 复制代码
@Service
public class UserService {

    @Autowired
    private Cache<String, User> userCache;

    public User getUser(String id) {
        return userCache.get(id, this::loadUserFromDB);
    }

    private User loadUserFromDB(String id) {
        // 模拟 DB 查询
        return new User(id, "Name-" + id);
    }
}

💡 提示 :Spring 6+ 已内置 CaffeineCacheManager,可直接用 @Cacheable 注解。


九、常见误区与避坑指南

❌ 误区 1:缓存所有数据

  • 问题:内存爆炸(OOM)
  • 正确做法 :只缓存热点、小、读多写少的数据

❌ 误区 2:不设过期时间

  • 问题:脏数据长期滞留
  • 正确做法 :必须设置 expireAfterWriteexpireAfterAccess

❌ 误区 3:用于分布式场景

  • 问题:每个 JVM 实例缓存独立,数据不一致
  • 正确做法本地缓存 + Redis 组成多级缓存

十、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
宸津-代码粉碎机18 分钟前
Spring Boot 4.0 实战技巧全解析
java·大数据·spring boot·后端·python
Makoto_Kimur19 分钟前
Java Scanner 的 ACM 常用输入模板
java·数据结构·算法
0xDevNull23 分钟前
Spring 核心教程:@Component vs @Bean 深度解析
java·后端
小碗羊肉26 分钟前
【从零开始学Java | 第三十二篇】方法引用(Method Reference)
java·开发语言
满满和米兜32 分钟前
【Java基础】- 集合-HashSet与TreeSet
java·开发语言·算法
网安INF43 分钟前
数据结构第二章复习:线性表
java·开发语言·数据结构
aq55356001 小时前
Laravel10.X核心特性全解析
java·开发语言·spring boot·后端
锦瑟弦音1 小时前
Java与SQL基础知识总结
java·开发语言
停水咋洗澡1 小时前
Redis Sentinel高可用实战:主从自动故障转移
java·redis·sentinel