Java guava框架LoadingCache及CacheBuilder本地小容量缓存框架总结

 更新时间:2023年12月22日 11:56:09   作者:极光雨雨  
Guava Cache本地缓存框架主要是一种将本地数据缓存到内存中,但数据量并不能太大,否则将会占用过多的内存,本文给大家介绍Java guava框架 LoadingCache及CacheBuilder 本地小容量缓存框架总结,感兴趣的朋友一起看看吧

Guava Cache本地缓存框架介绍

主要是一种将本地数据缓存到内存中,但数据量并不能太大,否则将会占用过多的内存,虽然框架本身已经做了相当的数据回收,但还是不可以滥用,需要符合以下优点场景,才是合适使用,访问内存的速度快于访问 redis 等数据库。

有点以及需求场景:

  • 对性能有非常高的要求
  • 愿意消耗一些内存空间来提升速度
  • 预计到某些键会被多次查询
  • 缓存中存放的数据总量不会超出内存容量

关键点是:有频繁访问的数据,且这些数据本身占用内存量很少,将这些数据存储到该缓存框架中管理以提供性能

提供的优势能力

  • 缓存可以设置过期时间,并提供数据过多时的淘汰机制
  • 是线程安全的,支持并发读入和写入
  • 缓存获取不到时可以从数据源获取并加入到缓存中,GuavaCache 可以使用 CacheLoader 的load 方法控制,对同一个key,只允许一个请求去读源并回填缓存,其他请求阻塞等待
  • 可以查看缓存的加载获取信息等

使用以及方法

Maven 依赖:

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>20.0</version>
        </dependency>

最简单的构建案例

Cache<String, Object> cache = CacheBuilder.newBuilder().build();
cache.put("aaa", 156484);

Map类似,获取时使用get() 方法即可获取到放入其中的数据。

通过 CacheBuilder 创建 Cache 对象,存储类似于Map 构建方法为链式构造,类似于 builder 建造者模式,返回均为当前对象本身,调用 build 方法后结束构造。

CacheBuilder.newBuilder() 后的一些构建参数方法介绍:

initialCapacity:缓存的初始数据容量大小,一般要贴合实际否则会造成资源浪费
maximumSize:缓存中可包含最大 entry 数量,超过数量限制后淘汰 entry,接近最大值时淘汰不常用数据,设置为 0 时为不使用缓存的场景,用于测试数据加载

过期时间设置

expireAfterAccess:数据写入后被访问对象多久没被访问认为过期
expireAfterWrite: 数据被写入到缓存后一直未更新多久后过期

可以如下写:

        Cache<String, Object> cache = CacheBuilder.newBuilder()
                .initialCapacity(5)
                .maximumSize(10)
                .expireAfterWrite(10, TimeUnit.MINUTES).build();
		cache.put("154", "djawbdawd");

过期时间单位通过 TimeUnit 后的控制,时分秒均可

弱软引用 (weakKeys, weakValues, softValues)

weakKeys
将缓存中的key设置成weakKey模式。
默认情况下,会使用“强关系”来保存key值。当设置为weakKey时,会使用 “==” 来匹配key值。在使用weakKey的情况下,数据可能会被GC。数据被GC后,可能仍然会被size方法计数,但是对其执行read或write方法已经无效。

weakValues
将缓存中的数据设置为weakValues模式。
启用时,某些数据会被GC。默认情况下会使用“强关系”来保存key值。当设置为weakValue时,会使用 “==” 来匹配value值。数据被GC后,可能仍然会被size方法计数,但是对其执行read或write方法已经无效。

softValues
将缓存中的数据设置为softValues模式。
启用时,所有的数据都使用SoftReference类对缓存中的数据进行包裹(就是在SoftReference实例中存储真实的数据)。使用SoftReference包裹的数据,会被全局垃圾回收管理器托管,按照LRU的原则来定期GC数据。数据被GC后,可能仍然会被size方法计数,但是对其执行read或write方法已经无效。

这些同样在 CacheBuilder.newBuilder() 后设置。

主动删除数据

当通过 builder 创建对象完成后,可以通过以下方式清除数据:
invalidateAll:清除全部数据,入参为 Iterable 类型参数,即 一般的List 集合即可,内容为所有的 key
invalidate:单一删除,入参为 key

删除监听器

即用于监控缓存中的数据,当数据被删除时会被触发
类似如下代码:

        RemovalListener<String, String> listener = new RemovalListener<String, Object>() {
            public void onRemoval(RemovalNotification<String, String> notification) {
            // notification.getKey();  // 当前删除对象的 key
            // notification.getValue();  // 当前删除对象的 value
            }
        };
        Cache<String, Object> cache = CacheBuilder.newBuilder()
                .maximumSize(5)
                // 添加移除监听器
                .removalListener(listener) 
                .build();

值得注意的是,这里的删除不仅是主动删除,当达到容量上限或者过期或由于其他策略导致数据消失时也认为是删除

一般cache 主动加载数据

即当缓存中获取不到指定 key 对应的 value 时,需要主动去其他途径获取:

写法类似如下,需要提供获取的实现方法:

Cache<String, Object> cache = CacheBuilder.newBuilder()
                .initialCapacity(5)
                .maximumSize(10)
                .expireAfterWrite(10, TimeUnit.MINUTES).build();
        cache.put("154", "djawbdawd");
        try {
            cache.get("aaa", new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    // 具体如何获取
                    // 方法的返回值即为 当前key 对应的value 并将会加入到缓存中
                    return null;
                }
            });
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

需要在 Callable 内的方法重写获取实际数据的方法,方法的返回值即为 当前key 对应的value 并将会加入到缓存中,同时如果存在多个线程同时获取同一个不存在的 key,那么将只有一个被执行,其他需要等待。且一个线程获取后,其他线程将也可以获取这些数据。

统计信息

创建cache 对象时调用**.recordStats()** 后将开启统计,可以通过 cache.stats() 获取缓存
例如:

        Cache<String, Object> cache = CacheBuilder.newBuilder()
                .initialCapacity(5)
                .maximumSize(10)
                .recordStats()
                .expireAfterWrite(10, TimeUnit.MINUTES).build();
        cache.put("154", "djawbdawd");
        try {
            cache.get("aaa", new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    // .......
                    return null;
                }
            });
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        cache.stats();

较常用的 LoadingCache

LoadingCache 是 Cache的子接口 ,相比于Cache,当从LoadingCache中读取一个指定key的记录时,如果该记录不存在,则LoadingCache可以自动执行加载数据到缓存的操作,定义时需要重写加载方法。
LoadingCache接口的定义如下:

CacheLoader<String, String> loader = new CacheLoader<>() {
		// 加载没有的数据的方法
            public String load(String key) throws Exception {
            // .............
                return null;
            }
        };
        LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
                .maximumSize(5)
                .build(loader);

或如下:

LoadingCache<String, Object> infoItemCache = CacheBuilder.newBuilder()
		.initialCapacity(5)
		.maximumSize(10)
		.expireAfterAccess(3, TimeUnit.MINUTES).build(new CacheLoader<String, Object>() {
                    // 使用 LoadingCache 重写加载方法, 重写后当无法从缓存中获取到key 对应的值时将执行重写的load 方法,且返回值将成为入参key 对应的Value并存储
                    @Override
                    public Object load(String s) throws Exception {
                        // ............
                        return null;
                    }
                });

可以自定义简单工具如下:

import com.dtdream.dthink.dtalent.dmall.dataresource.catalog.model.metadata.MetadataBlock;
import com.dtdream.dthink.dtalent.dmall.dataresource.catalog.service.catalog.ICatalogTemplateService;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class MyCache {
    /**
     * 初始化缓存容量大小
     */
    private static final int INITIAL_CAPACITY = 5;
    /**
     * 缓存中可包含最大 entry 数量,超过数量限制后淘汰 entry,接近最大值时淘汰不常用数据,设置为 0 时为不使用缓存的场景,用于测试数据加载
     */
    private static final long MAXIMUM_SIZE = 10;
    /**
     * 放入缓存后指定时间内没有被访问将过期
     */
    private static final long EXPIRE_AFTER_ACCESS = 5;
    /**
     * cache 子接口, 缓存对象
     */
    private static LoadingCache<String, Object> infoItemCache;
    // 初始化缓存对象
    static {
        infoItemCache = CacheBuilder.newBuilder().initialCapacity(INITIAL_CAPACITY).maximumSize(MAXIMUM_SIZE)
                .expireAfterAccess(EXPIRE_AFTER_ACCESS, TimeUnit.MINUTES).build(new CacheLoader<String, Object>() {
                    // 使用 LoadingCache 重写加载方法, 重写后当无法从缓存中获取到key 对应的值时将执行重写的load 方法,且返回值将成为入参key 对应的Value并存储
                    @Override
                    public Object load(String s) throws Exception {
                        // ...............
                        return null;
                    }
                });
    }
    /**
     * 从缓存中获取数据,若不存在则重新查询
     * @return
     */
    public static Object getFromCache(String key) throws ExecutionException {
        Object data = infoItemCache.get(key);
        return data;
    }
}

若需要从Spring 获取Bean 服务,则可以通过 Spring 的 applicationConext 去获取

到此这篇关于Java guava框架 LoadingCache,CacheBuilder 本地小容量缓存框架学习以及总结的文章就介绍到这了,更多相关Java guava框架 LoadingCache内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于Java反射机制 你需要知道的事情

    关于Java反射机制 你需要知道的事情

    这篇文章主要介绍了Java反射机制的相关内容,涉及了class类的动态加载,获取成员变量、构造函数信息等信息,需要的朋友可以参考下。
    2017-09-09
  • java打印当前方法名示例分享

    java打印当前方法名示例分享

    在C与C++中可以打印当前函数名,但在Java没有此说法,一切即对象,得从某个对象中去获取,下面介绍两种方式打印当前方法名
    2014-02-02
  • 基于Jenkins搭建.NET Core持续集成环境过程图解

    基于Jenkins搭建.NET Core持续集成环境过程图解

    这篇文章主要介绍了基于Jenkins搭建.NET Core持续集成环境过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Java实现简单客户信息管理系统

    Java实现简单客户信息管理系统

    这篇文章主要为大家详细介绍了Java实现简单客户信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • Spring连接Mysql数据库的实现步骤

    Spring连接Mysql数据库的实现步骤

    本文主要介绍了Spring连接Mysql数据库的实现步骤,文中根据实例编码详细介绍的十分详尽,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Java多线程之同步锁-lock详解

    Java多线程之同步锁-lock详解

    这篇文章主要为大家详细介绍了Java多线程中同步锁-lock的原理与使用,文中的示例代码讲解详细,对我们了解线程有一定帮助,需要的可以参考一下
    2022-10-10
  • java文件操作代码片断实例实现统计文件中字母出现的个数功能

    java文件操作代码片断实例实现统计文件中字母出现的个数功能

    本文介绍java读文件实例,实现统计某一目录下每个文件中出现的字母个数、数字个数、空格个数及行数,除此之外没有其他字符,大家参考使用吧
    2014-01-01
  • Druid(新版starter)在SpringBoot下的使用教程

    Druid(新版starter)在SpringBoot下的使用教程

    Druid是Java语言中最好的数据库连接池,Druid能够提供强大的监控和扩展功能,DruidDataSource支持的数据库,这篇文章主要介绍了Druid(新版starter)在SpringBoot下的使用,需要的朋友可以参考下
    2023-05-05
  • Java中的transient关键字解析

    Java中的transient关键字解析

    这篇文章主要介绍了Java中的 transient关键字解析,有时候我们的一些敏感信息比如密码并不想序列化传输给对方,这个时候transient关键字就派上用场了,如果一个类的变量加上了transient关键字那么这个字段就不会被序列化,需要的朋友可以参考下
    2023-09-09
  • SpringMVC拦截器创建配置及执行顺序

    SpringMVC拦截器创建配置及执行顺序

    这篇文章主要为大家介绍了SpringMVC拦截器创建配置及执行顺序,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05

最新评论