Guava Cache 工具类 [ GuavaCacheUtil ]

本文深入探讨了Guava缓存库的使用方法,详细介绍了如何配置缓存的最大容量、有效时间和缓存回收策略。同时,提供了丰富的示例代码,展示了如何进行缓存的增删查改操作,并监控缓存的命中率和加载时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


pom.xml


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


GuavaCacheUtil.java


package com.app.core.util;

import com.google.common.cache.*;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

@Log4j2
public class GuavaCacheUtil {
    /**
     * 缓存项最大数量
     */
    private static final long GUAVA_CACHE_SIZE = 100000;
    /**
     * 缓存时间:分钟
     */
    private static final long GUAVA_CACHE_TIME = 10;

    /**
     * 缓存操作对象
     */
    private static LoadingCache<String, Object> GLOBAL_CACHE = null;

    static {
        try {
            GLOBAL_CACHE = loadCache(new CacheLoader<String, Object>() {
                public Object load(String key) throws Exception {
                    // 该方法主要是处理缓存键不存在缓存值时的处理逻辑
                    if (log.isDebugEnabled())
                        log.debug("Guava Cache缓存值不存在,初始化空值,键名:{}", key);
                    return ObjectUtils.NULL;
                }
            });
        } catch (Exception e) {
            log.error("初始化Guava Cache出错", e);
        }
    }

    /**
     * 全局缓存设置
     * <ul>
     * <li>缓存项最大数量:100000</li>
     * <li>缓存有效时间(分钟):10</li>
     * </ul>
     *
     * @param cacheLoader
     * @return
     * @throws Exception
     */
    private static <K, V> LoadingCache<K, V> loadCache(CacheLoader<K, V> cacheLoader) throws Exception {
        /*
         * maximumSize 缓存池大小,在缓存项接近该大小时, Guava开始回收旧的缓存项 expireAfterAccess 表示最后一次使用该缓存项多长时间后失效 removalListener 移除缓存项时执行的逻辑方法 recordStats 开启Guava Cache的统计功能
         */
        LoadingCache<K, V> cache = CacheBuilder.newBuilder().maximumSize(GUAVA_CACHE_SIZE).expireAfterAccess(GUAVA_CACHE_TIME, TimeUnit.MINUTES)
                .removalListener(new RemovalListener<K, V>() {
                    public void onRemoval(RemovalNotification<K, V> rn) {
                        if (log.isDebugEnabled())
                            log.debug("Guava Cache缓存回收成功,键:{}, 值:{}", rn.getKey(), rn.getValue());
                    }
                }).recordStats().build(cacheLoader);
        return cache;
    }

    /**
     * 设置缓存值
     *
     * @param key
     * @param value
     */
    public static void put(String key, Object value) {
        try {
            GLOBAL_CACHE.put(key, value);
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("设置缓存值出错", e);
        }
    }

    /**
     * 批量设置缓存值
     *
     * @param map
     */
    public static void putAll(Map<? extends String, ? extends Object> map) {
        try {
            GLOBAL_CACHE.putAll(map);
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("批量设置缓存值出错", e);
        }
    }

    /**
     * 获取缓存值
     * <p>注:如果键不存在值,将调用CacheLoader的load方法加载新值到该键中</p>
     *
     * @param key
     * @return
     */
    public static Object get(String key) {
        Object obj = null;
        try {
            obj = GLOBAL_CACHE.get(key);
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("获取缓存值出错", e);
        }
        return obj;
    }

    /**
     * 获取缓存值
     * <p>注:如果键不存在值,将直接返回 NULL</p>
     *
     * @param key
     * @return
     */
    public static Object getIfPresent(String key) {
        Object obj = null;
        try {
            obj = GLOBAL_CACHE.getIfPresent(key);
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("获取缓存值出错", e);
        }
        return obj;
    }

    /**
     * 移除缓存
     *
     * @param key
     */
    public static void remove(String key) {
        try {
            GLOBAL_CACHE.invalidate(key);
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("移除缓存出错", e);
        }
    }

    /**
     * 批量移除缓存
     *
     * @param keys
     */
    public static void removeAll(Iterable<String> keys) {
        try {
            GLOBAL_CACHE.invalidateAll(keys);
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("批量移除缓存出错", e);
        }
    }

    /**
     * 清空所有缓存
     */
    public static void removeAll() {
        try {
            GLOBAL_CACHE.invalidateAll();
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("清空所有缓存出错", e);
        }
    }

    /**
     * 获取缓存项数量
     *
     * @return
     */
    public static long size() {
        long size = 0;
        try {
            size = GLOBAL_CACHE.size();
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("获取缓存项数量出错", e);
        }
        return size;
    }

    /**
     * 获取所有缓存项的键
     *
     * @return
     */
    public static List<String> keys() {
        List<String> list = new ArrayList<String>();
        try {
            ConcurrentMap<String, Object> map = GLOBAL_CACHE.asMap();
            for (Map.Entry<String, Object> item : map.entrySet())
                list.add(item.getKey());
            if (log.isDebugEnabled())
                log.debug("缓存命中率:{},新值平均加载时间:{}", getHitRate(), getAverageLoadPenalty());
        } catch (Exception e) {
            log.error("获取所有缓存项的键出错", e);
        }
        return list;
    }

    /**
     * 缓存命中率
     *
     * @return
     */
    public static double getHitRate() {
        return GLOBAL_CACHE.stats().hitRate();
    }

    /**
     * 加载新值的平均时间,单位为纳秒
     *
     * @return
     */
    public static double getAverageLoadPenalty() {
        return GLOBAL_CACHE.stats().averageLoadPenalty();
    }

    /**
     * 缓存项被回收的总数,不包括显式清除
     *
     * @return
     */
    public static long getEvictionCount() {
        return GLOBAL_CACHE.stats().evictionCount();
    }
}

### Guava Cache 的使用指南与实现示例 Guava Cache 是 Google 提供的一个本地缓存工具类,适用于 Java 应用程序,可以用来缓存数据,从而减少重复计算或频繁访问数据库的开销。Guava Cache 提供了多种配置选项,包括最大缓存容量、过期时间以及自动加载机制等。以下将详细介绍 Guava Cache 的使用方法,并提供实现示例。 #### 创建缓存对象 在使用 Guava Cache 之前,需要通过 `CacheBuilder` 来创建一个缓存实例。`CacheBuilder` 允许开发者设置缓存的最大容量、过期时间以及其他参数。例如,可以通过 `maximumSize` 方法设置缓存的最大条目数,也可以通过 `expireAfterWrite` 或 `expireAfterAccess` 方法设置缓存条目的过期时间[^4]。 ```java import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; public class CacheExample { public static void main(String[] args) { // 创建一个最大容量为100的缓存,写入后10分钟过期 Cache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(100) .expireAfterWrite(10, TimeUnit.MINUTES) .build(); } } ``` #### 存储与获取缓存 一旦缓存对象创建完成,就可以使用 `put` 方法手动将数据存入缓存中。此外,还可以利用 `get` 方法结合 `Callable` 接口来实现缓存条目的自动加载功能。当请求的数据不在缓存中时,`get` 方法会调用提供的 `Callable` 对象来生成缺失的数据[^4]。 ```java // 存入缓存 cache.put("key1", "value1"); // 获取缓存 String value1 = cache.getIfPresent("key1"); System.out.println("Value1: " + value1); // 获取缓存,如果不存在则通过Callable加载 try { String value3 = cache.get("key3", () -> { // 模拟从数据库或其他数据源加载数据 System.out.println("Loading value3..."); return "value3"; }); System.out.println("Value3: " + value3); } catch (Exception e) { e.printStackTrace(); } ``` #### 移除缓存条目 当不再需要某个缓存条目时,可以使用 `invalidate` 方法将其从缓存中移除。如果希望一次性清除所有缓存条目,可以调用 `invalidateAll` 方法[^4]。 ```java // 移除特定缓存 cache.invalidate("key1"); // 获取缓存,此时应返回null System.out.println("Value1 after invalidate: " + cache.getIfPresent("key1")); ``` #### 定期清理过期缓存 虽然 Guava Cache 提供了基于时间的自动过期机制,但并不会立即清理过期的条目。相反,它会在进行读写操作时顺带执行清理工作。如果需要更及时地清理过期数据,可以在后台启动一个定时任务来定期调用 `cleanUp` 方法[^2]。 ```java // 定期清理过期缓存 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); executor.scheduleAtFixedRate(cache::cleanUp, 0, 5, TimeUnit.MINUTES); ``` ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值