Spring Boot对GuavaCache中LoadingCache的使用

目录

前言

一、概述

CacheBuilder方法参数

CacheLoader

二、环境依赖

三、示例代码

总结 


前言

LoadingCache是GuavaCache构建缓存实体的方法,是一个支持多线程并发读写、高性能、通用的in-heap(堆)本地缓存。
支持key不存在时按照给定的CacheLoader 的loader方法进行loading。如果有多个线程同时get一个不存在的key,那么会有一个线程负责load,其他线程阻塞wait等待。

在工作总常常需要用到缓存,而redis往往是首选,但是短期的数据缓存一般我们还是会用到本地缓存。本文提供一个我在工作中用到的缓存工具,该工具代码为了演示做了一些调整。如果拿去使用的话,可以考虑做成注入Bean对象,看具体需求了。

本次介绍GuavaCache中LoadingCache

一、概述

CacheBuilder方法参数

三种刷新本地缓存的机制:
expireAfterAccess:当缓存项在指定的时间段内没有被读或写就会被回收。
expireAfterWrite:当缓存项在指定的时间段内没有更新就会被回收。-- 常用
refreshAfterWrite:当缓存项上一次更新操作之后的多久会被刷新。 -- 常用

maximumSize(): 最大缓存上限,快达到上限或达到上限,处理了时间最长没被访问过的对象或者根据配置的被释放的对象

CacheLoader

实现自动加载缓存。可以在其中自定义load方法和reload方法,根据需求加载缓存和刷新缓存。

二、环境依赖

Maven版本依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

三、示例代码

@Slf4j
@Component
public class LoadingCacheUtil implements ApplicationContextAware{

    private static ApplicationContext applicationContext;

    /** 缓存项最大数量 */
    private static final long GUAVA_CACHE_SIZE = 10000;
    /** 缓存时间:分钟 */
    private static final long GUAVA_CACHE_MINUTES = 10;
    /** 缓存操作对象 */
    private static LoadingCache<String, Object> GLOBAL_CACHE = null;

    static {
        try {
            GLOBAL_CACHE = loadCache(new CacheLoader <String, Object>() {
                @Override
                public Object load(String key) throws Exception {
                    // 这里是如果使用loadingCache.get(key)或者这里是如果使用loadingCache.getUnchecked(key)获取
                    // 残存中数据时,如果为空,则自动会放入LoadingCache内存缓存中,return值就是放入内存缓存中的值
                    // 同时设置的expireAfterWrite缓存失效策略,超过过期时间,也会自动将这个方法return数据加入放入内存缓存
                    //因在静态代码块内,所以需要applicationContext获取service层的实现类方法
                    Service service = applicationContext.getBean(ServiceImpl.class);
                    // 处理缓存键不存在缓存值时的处理逻辑
                    /* 在这里写具体业务实现,在service层调用get(key)方法即可 */
                    return null;
            });
        } catch (Exception e) {
            log.error("初始化Guava Cache出错", e);
        }
    }

    /**
     * 全局缓存设置
     * 缓存项最大数量:100000
     * 缓存有效时间(分钟):10
     * @param cacheLoader
     * @return
     * @throws Exception
     */
    private static LoadingCache<String, Object> loadCache(CacheLoader<String, Object> cacheLoader)
            throws Exception {
        LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
                //缓存池大小,在缓存项接近该大小时, Guava开始回收旧的缓存项
                .maximumSize(GUAVA_CACHE_SIZE)
                //设置时间对象没有被读/写访问则对象从内存中删除(在另外的线程里面不定期维护)
                .refreshAfterWrite(GUAVA_CACHE_MINUTES, TimeUnit.MINUTES)
                .build(cacheLoader);
        return cache;
    }

    /**
     * 设置缓存值
     * 注: 若已有该key值,则会先移除(会触发removalListener移除监听器),再添加
     *
     * @param key
     * @param value
     */
    public static void put(String key, Object value) {
        try {
            GLOBAL_CACHE.put(key, value);
        } catch (Exception e) {
            log.error("设置缓存值出错", e);
        }
    }

    /**
     * 获取缓存值
     * 注:如果键不存在值,将调用CacheLoader的load方法加载新值到该键中
     *
     * @param key
     * @return
     */
    public static Object get(String key) {
        Object token = "";
        try {
            token = GLOBAL_CACHE.get(key);
        } catch (Exception e) {
            log.error("获取缓存值出错", e);
        }
        return token;
    }

    /**
     * 刷新指定缓存值
     * @param key
     */
    public static void reload(String key) {
        try {
            GLOBAL_CACHE.refresh(key);
        } catch (Exception e) {
            log.error("缓存刷新错误", e);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(this.applicationContext==null){
            this.applicationContext = applicationContext;
        }
    }
    // 获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    /**
     * 通过name获取Bean
     *
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws BeansException
     */
    public static Object getBean(String name) throws BeansException {
        return getApplicationContext().getBean(name);
    }
}
注 :在字符串转成数组的过程中可能会出现类型转换异常,原因为数据为空。可以做以下处理:
        try {
            return (List<VO>) LoadingCacheUtil.get(key);
        } catch (ClassCastException e){
            // java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
            // 转换失败,即数据为空,无法将字符串转成数组,为空直接跳过当前即可
            List<VO> resultList = new ArrayList<>();
            return resultList;
        }

总结 

 短期的数据缓存使用本地缓存LoadingCache做缓存还是不错的

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值