Caffeine缓存

2024-09-04 09:36:37 浏览数 (1)

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

  1. 项目介绍

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

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

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

  • 自动加载元素到缓存当中,异步加载的方式也可供选择
  • 当达到最大容量的时候可以使用基于就近度和频率的算法进行基于容量的驱逐
  • 将根据缓存中的元素上一次访问或者被修改的时间进行基于过期时间的驱逐
  • 当向缓存中一个已经过时的元素进行访问的时候将会进行异步刷新
  • key将自动被弱引用所封装
  • value将自动被弱引用或者软引用所封装
  • 驱逐(或移除)缓存中的元素时将会进行通知
  • 写入传播到一个外部数据源当中
  • 持续计算缓存的访问统计指标

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

  1. 官方文档、GitHub地址
  • 官方网站:Caffeine Documentation
  • GitHub仓库:ben-manes/caffeine

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

  1. 引入依赖

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

对于 Maven 用户:

代码语言:javascript复制
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version>
</dependency>

对于 Gradle 用户:

代码语言:javascript复制
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'

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

  1. 例子

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

示例:用户信息缓存

代码语言:javascript复制
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() 获取缓存的统计数据,包括命中次数、未命中次数等。

运行结果:

代码语言:javascript复制
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 官方文档:高级用法
  • 使用 Caffeine 实现 Spring Cache

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

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

0 人点赞