好用的Java内存缓存库,Guava Cache

2023年 10月 16日 78.7k 0

一、引言

内存缓存是一种在内存中临时存储数据的机制,它能加速数据访问,提升应用程序的响应性能。

通过将经常访问的数据保存在快速访问的内存中,可以减少昂贵的磁盘或网络访问。内存缓存还能减轻数据源负载,提高系统稳定性和可扩展性。

然而,使用内存缓存需要仔细考虑缓存策略、过期时间、一致性等问题,以确保缓存的有效性。

合理的缓存设计和配置能充分发挥内存缓存的优势,提供更好的应用体验。

作为一个开发,多多少少都对内存缓存有一些了解。可能更多的人在工作中接触的更多的是memcacheredis这些内存缓存系统。这些系统都是需要额外部署的,需要使用客户端链接,查询和存储的时候也会增加我们的网络开销。

今天我们来认识一个基于JVM的内存缓存库:Guava Cache

二、Guava Cache是什么

Guava Cache是Google Guava库中提供的一个内存缓存库。旨在提供简单而高效的内存缓存解决方案。为Java开发人员提供了一种方便的方式来实现内存缓存,以改善应用程序的性能和响应性。

Guava Cache提供了一种可配置的缓存机制,可以将经常访问的数据存储在内存中,以提高数据访问的速度和性能。它支持设置缓存的最大大小、过期策略、自动加载数据等功能。缓存可以自动管理数据的过期和淘汰策略,以确保缓存中的数据是最新和有效的。

使用Guava Cache,开发人员可以轻松地在应用程序中集成内存缓存功能,以加速数据访问和提升应用程序的性能。它适用于各种本地缓存需求,并提供了简单的API和配置选项来满足不同的使用场景。通过减少对耗时的数据源访问,Guava Cache可以显著提升应用程序的响应性能,并减轻对后端资源的负载。

2.1 Guava Cache 的主要概念和特点

graph LR
A(Guava Cache 的主要概念和特点) 
B(Google Guava 库中的一个功能模块)
C(简单而高效的内存缓存解决方案)
D(提高访问速度和性能)
E(配置选项)
EA(最大大小)
EB(过期策略)
EC(数据加载方式)
F(自动管理)
FA(过期和淘汰策略)
FB(数据有效性和一致性)
G(优势)
GA(API简单)
GB(减少耗时的数据源访问)
GC(提升应用程序的响应性能)
H(强大,性能改善)

A ---> B
A ---> C
A ---> D
A ---> E
E ---> EA
E ---> EB
E ---> EC
A ---> F
F ---> FA
F ---> FB
A ---> G
G ---> GA
G ---> GB
G ---> GC
A ---> H

style GB fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style GC fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style GA fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style FB fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style FA fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style EB fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style EC fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style EA fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
style F fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
style G fill:#00FFFF,stroke:#00FFFF,stroke-width:2px
style H fill:#E6E6FA,stroke:#E6E6FA,stroke-width:2px
  • Guava Cache 是 Google Guava 库中的一个功能模块。

  • Guava Cache 提供了简单而高效的内存缓存解决方案。

  • Guava Cache 允许将经常访问的数据存储在内存中,以提高访问速度和性能。

  • 可以配置 Guava Cache 的最大大小、过期策略和数据加载方式。

  • 缓存中的数据可以自动管理过期和淘汰策略,确保数据的有效性和一致性。

  • Guava Cache 适用于各种本地缓存需求,提供简单的 API 和配置选项。

  • 使用 Guava Cache 可以减少对耗时的数据源访问,提升应用程序的响应性能。

  • Guava Cache 是一个简单而强大的内存缓存库,改善应用程序的性能和响应性。

三、怎么使用Guava Cache

在项目中使用Guava Cache的时候,实际是有一些固定的操作姿势,下面我们来认识一下一般情况下我们都是怎么操作的。

3.1 使用流程图

sequenceDiagram
    participant A1 as Java项目
    participant A as 任务线程
    participant B as Guava Cache
    participant C as 监听器线程
    
A1 ->> A1: 引入依赖
A1 ->> A: 启动任务
A ->> B: 创建Cache实例
B ->> B: 数据加载
A ->> B: 存储数据
A ->> B: 获取数据
A ->> B: 移除数据
A ->> B: 清空Cache
C ->> B: 添加监听器
C ->> B: 数据过期或者被移除逻辑

3.2 使用的详细步骤分解

  • 添加Guava库依赖:在你的项目中添加Guava库的依赖,以便能够使用Guava Cache。你可以从Maven中央仓库或Gradle依赖中心下载Guava相关的库文件。
  • 
    
        com.google.guava
        guava
        32.1.2-jre
    
    
  • 创建Cache实例:使用Guava Cache提供的CacheBuilder类创建一个Cache实例。你可以通过链式调用方法来配置Cache的属性,例如最大大小、过期策略等。
  • Cache cache = CacheBuilder.newBuilder()
        .maximumSize(100)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .build();
    

    上面代码代码创建了一个具有最大大小限制和过期时间的缓存对象,我们来详细分析一下:

    • 首选 Cache cache = CacheBuilder.newBuilder():这行代码创建了一个新的 CacheBuilder 对象,并将其分配给变量 cache。CacheBuilder 是 Guava 提供的用于构建缓存对象的构建器类。

    • 然后 .maximumSize(100):这行代码设置了缓存的最大大小为 100。这意味着当缓存中的元素数量达到最大值时,新的元素将会替换掉最旧的元素。

    • 其次 .expireAfterWrite(10, TimeUnit.MINUTES):这行代码设置了缓存项在写入后的存活时间为 10 分钟。换句话说,如果某个缓存项在 10 分钟内没有被读或写操作访问,那么该缓存项将会被自动移除。

    • 最后 .build():这行代码完成了缓存对象的构建,并返回最终的 Cache 对象。

  • 存储数据:使用put(key, value)方法将数据存储到Cache中。你可以使用自定义的键(Key)和值(Value)类型。
  • cache.put(key, value);
    
  • 获取数据:使用getIfPresent(key)方法从Cache中获取数据。如果数据存在于Cache中,则返回对应的值;否则返回null。
  • Value value = cache.getIfPresent(key);
    
  • 数据加载:如果需要自动加载数据到Cache中,你可以使用get(key, Callable)方法。当缓存中不存在对应的值时,Guava Cache会自动调用提供的Callable对象来加载数据。
  • Value value = cache.get(key, new Callable() {
        public Value call() throws Exception {
            // 数据加载逻辑
            return loadDataByDb(key);
        }
    });
    
  • 移除数据:你可以使用invalidate(key)方法从Cache中移除指定的键值对。
  • cache.invalidate(key);
    
  • 清空Cache:如果需要清空整个Cache,你可以使用invalidateAll()方法。
  • cache.invalidateAll();
    
  • 监听器:Guava Cache还支持添加监听器,以便在数据被移除或过期时执行自定义逻辑。你可以实现RemovalListener接口并注册监听器。
  • RemovalListener listener = new RemovalListener() {
        public void onRemoval(RemovalNotification notification) {
            // 执行自定义逻辑
        }
    };
    cacheBuilder.removalListener(listener);
    

    四、实际操作中,Google Guava的几种过期策略如何实现

    Google Guava 提供了多种过期策略来管理缓存项的过期和失效。下面来介绍一下 Guava 中几种常用的过期策略及其实现方式。

    老规矩,先来张图看看都有那些过期策略:

    graph LR
    A(Google Guava过期策略)
    B(基于时间)
    C(写入时间)
    D(访问时间)
    E(基于大小)
    F(基于引用)
    G(基于提醒)
    
    A ---> B
    B ---> C
    B ---> D
    A ---> E
    A ---> F
    A ---> G
    
    style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
    style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
    style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
    style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
    style F fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
    style G fill:#00FFFF,stroke:#00FFFF,stroke-width:2px
    

    4.1 基于时间的过期策略

    可以通过 expireAfterWrite() 和 expireAfterAccess() 方法来设置缓存项的写入后过期时间和最后访问后过期时间。

    • expireAfterWrite(duration, unit):设置缓存项在写入后的过期时间。过期时间从写入操作发生后开始计算。
    Cache cache = CacheBuilder.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES) // 缓存项在写入后10分钟过期
            .build();
    
    cache.put("key", "value");
    
    // 在10分钟内访问缓存项,它仍然有效
    String value = cache.getIfPresent("key");
    
    // 10分钟后,缓存项过期,再次访问将返回null
    value = cache.getIfPresent("key");
    
    • expireAfterAccess(duration, unit):设置缓存项在最后访问后的过期时间。过期时间从最后一次访问操作发生后开始计算。
    Cache cache = CacheBuilder.newBuilder()
            .expireAfterAccess(5, TimeUnit.MINUTES) // 缓存项在最后一次访问后5分钟过期
            .build();
    
    cache.put("key", "value");
    
    // 在5分钟内多次访问缓存项,它仍然有效
    String value = cache.getIfPresent("key");
    value = cache.getIfPresent("key");
    value = cache.getIfPresent("key");
    
    try {
        // 休眠5分钟
        Thread.sleep(5 * 60 * 1000);
    } catch (InterruptedException e) {
        // 处理中断异常
        e.printStackTrace();
    }
    
    // 5分钟后,没有再次访问缓存项,它过期并被自动移除
    // 再次尝试获取缓存项将返回null
    value = cache.getIfPresent("key"); // 返回null
    

    注意:这两种策略可以根据指定的时间单位(如分钟、小时、天等)来设置过期时间。

    4.2 基于大小的过期策略

    可以通过 maximumSize() 方法设置缓存的最大大小限制。当缓存项数量达到最大值时,新的元素将会替换掉最旧的元素。

    Cache cache = CacheBuilder.newBuilder()
            .maximumSize(100) // 缓存最大容量为100
            .build();
    
    for (int i = 0; i < 150; i++) {
        cache.put("key" + i, "value" + i);
    }
    
    // 在缓存容量达到100后,新的缓存项将替换最旧的缓存项
    String value = cache.getIfPresent("key0"); // 返回null,因为"key0"已被替换
    value = cache.getIfPresent("key100"); // 返回"value100",因为它仍然在缓存中
    

    4.3 基于引用的过期策略

    Guava 提供了 CacheBuilder 类中的 weakKeys() 和 weakValues() 方法,允许使用弱引用来存储缓存的键和值。当键或值不再被其他强引用引用时,缓存项将会被自动移除。

    • weakKeys():使用弱引用存储缓存的键。

    • weakValues():使用弱引用存储缓存的值。

    这些弱引用策略可用于在内存受限的情况下,允许缓存项根据垃圾回收的需要进行回收。

    Cache cache = CacheBuilder.newBuilder()
            .weakKeys() // 使用弱引用存储缓存的键
            .weakValues() // 使用弱引用存储缓存的值
            .build();
    
    String key = new String("key");
    Object value = new Object();
    
    cache.put(key, value);
    
    // 当key不再有其他强引用时,缓存项将被自动移除
    value = cache.getIfPresent(key); // 返回null,因为key已没有强引用
    

    4.4 基于提醒的过期策略

    通过 CacheBuilder 类的 expireAfterWrite() 方法结合 CacheBuilderSpec 类的 refreshAfterWrite() 方法,可以实现基于提醒的过期策略。该策略允许在缓存项过期时异步地加载新的值,并返回旧值。这样可以确保在缓存项过期时仍然能够返回旧值,同时异步加载新值,提高了缓存的命中率和性能。

    LoadingCache cache = CacheBuilder.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES) // 缓存项在写入后10分钟过期
            .refreshAfterWrite(1, TimeUnit.MINUTES) // 缓存项在写入后1分钟后异步刷新
            .build(new CacheLoader() {
                @Override
                public String load(String key) {
                    return "value"; // 在缓存项过期时异步加载新的值
                }
            });
    
    String value = cache.get("key");
    
    // 10分钟内,获取缓存项将返回旧值,并异步加载新的值
    value = cache.get("key");
    
    // 10分钟后,缓存项过期,获取缓存项将返回新的值
    value = cache.get("key");
    

    五、总结

    Google Guava是一个功能强大的Java工具库,提供了丰富的工具和集合类、函数式编程支持、缓存和并发处理等功能,帮助开发人员编写高效、可靠和易维护的Java代码;而且一直在维护迭代升级,行业良心。

    更多操作请查看官方文档

    最后:如果你从本篇文章中学到一点点东西,麻烦发财的小手点一下赞,如有疑问或者错误,欢迎提出和指正。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论