初识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 组成多级缓存

十、结语

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

相关推荐
big_rabbit05022 小时前
java面试题整理
java·开发语言
刺客xs2 小时前
c++模板
java·开发语言·c++
C+-C资深大佬2 小时前
C++ 性能优化 专业详解
java·c++·性能优化
程序员老乔2 小时前
Java 新纪元 — JDK 25 + Spring Boot 4 全栈实战(三):虚拟线程2.0,电商秒杀场景下的并发革命
java·开发语言·spring boot
weixin_404157682 小时前
Java高级面试与工程实践问题集(四)
java·开发语言·面试
cyforkk3 小时前
Spring AOP 核心揭秘:ProceedingJoinPoint 与反射机制详解
java·python·spring
无限进步_3 小时前
【C++】单词反转算法详解:原地操作与边界处理
java·开发语言·c++·git·算法·github·visual studio
wyiyiyi3 小时前
【线性代数】对偶空间与矩阵转置及矩阵分解(Java讲解)
java·线性代数·支持向量机·矩阵·数据分析
czlczl200209253 小时前
Redis过期删除策略
数据库·redis·缓存