在现代应用中,缓存是提升性能和降低外部系统压力的关键组件。Google 提供的 Guava 是一款强大的 Java 工具库,其中的 Guava Cache 模块提供了灵活的本地缓存功能。
本文将通过封装 Guava Cache
,实现一个通用的缓存模板,帮助开发者快速构建可复用的缓存逻辑。
Guava Cache 功能强大,但如果每次使用都需要手动配置,可能会显得繁琐。通过封装一个抽象类,我们可以将常用的配置和逻辑提取出来,让子类只需实现数据加载逻辑即可,简化代码,提高复用性。
以下是优化后的 GuavaAbstractLoadingCache
实现:
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 通用的 Guava 缓存模板。
* 子类只需实现 fetchData(key) 方法,从外部数据源获取数据。
* 调用 getValue(key) 即可从缓存中获取数据,缓存失效时会自动加载。
*
* @param <K> 缓存键类型(必须实现 Serializable)
* @param <V> 缓存值类型
*/
public abstract class GuavaAbstractLoadingCache<K extends Serializable, V> {
private static final Logger logger = Logger.getLogger(GuavaAbstractLoadingCache.class.getName());
private final int maximumSize;
private final int expireAfterWriteDuration;
private final TimeUnit timeUnit;
private volatile LoadingCache<K, V> cache;
/**
* 默认构造函数,使用默认配置。
*/
protected GuavaAbstractLoadingCache() {
this(1000, 60, TimeUnit.MINUTES);
}
/**
* 自定义配置构造函数。
*
* @param maximumSize 最大缓存条数
* @param expireAfterWriteDuration 缓存过期时长
* @param timeUnit 时间单位
*/
protected GuavaAbstractLoadingCache(int maximumSize, int expireAfterWriteDuration, TimeUnit timeUnit) {
this.maximumSize = maximumSize;
this.expireAfterWriteDuration = expireAfterWriteDuration;
this.timeUnit = timeUnit;
}
/**
* 获取缓存实例。如果缓存未初始化,则进行初始化。
*
* @return 缓存实例
*/
private LoadingCache<K, V> getCache() {
if (cache == null) {
synchronized (this) {
if (cache == null) {
cache = CacheBuilder.newBuilder()
.maximumSize(maximumSize)
.expireAfterWrite(expireAfterWriteDuration, timeUnit)
.build(new CacheLoader<K, V>() {
@Override
public V load(K key) throws Exception {
return fetchData(key);
}
});
logger.info("缓存初始化成功:最大大小 = " + maximumSize + ", 过期时长 = " + expireAfterWriteDuration + " " + timeUnit); }
}
}
return cache;
}
/**
* 子类实现:从外部数据源获取数据。
*
* @param key 缓存键
* @return 数据值
* @throws Exception 如果获取数据失败
*/
protected abstract V fetchData(K key) throws Exception;
/**
* 从缓存中获取数据。若缓存失效或不存在,会调用 fetchData 自动加载。
*
* @param key 缓存键
* @return 数据值
*/
public V getValue(K key) {
try {
return getCache().get(key);
} catch (ExecutionException e) {
logger.log(Level.SEVERE, MessageFormat.format("缓存加载失败, key: {0}", key), e);
throw new RuntimeException("缓存加载失败", e);
}
}
/**
* 清空缓存并重新初始化。
*/
public synchronized void resetCache() {
if (cache != null) {
cache.invalidateAll();
cache = null;
logger.info("缓存已清空并重置");
}
}
}
highestSize
和 highestTime
。getValue
方法中,避免调用方处理过多异常。通过继承 GuavaAbstractLoadingCache
,我们可以快速实现具体的缓存逻辑。以下是一个简单的用户信息缓存示例。
import java.util.HashMap;
import java.util.Map;
/**
* 示例子类:实现一个用户信息缓存。
*/
public class UserCache extends GuavaAbstractLoadingCache<String, String> {
private static final Map<String, String> DATABASE = new HashMap<>();
static {
DATABASE.put("1", "Alice");
DATABASE.put("2", "Bob");
DATABASE.put("3", "Charlie");
}
@Override
protected String fetchData(String key) {
System.out.println("从外部数据源加载数据,key: " + key);
return DATABASE.getOrDefault(key, "Unknown User");
}
}
public class CacheExample {
public static void main(String[] args) {
// 创建缓存实例
UserCache userCache = new UserCache();
// 测试获取数据
System.out.println(userCache.getValue("1")); // 输出:Alice
System.out.println(userCache.getValue("2")); // 输出:Bob
System.out.println(userCache.getValue("4")); // 输出:Unknown User
// 测试缓存功能(第二次获取不需要从数据源加载)
System.out.println(userCache.getValue("1")); // 输出:Alice (缓存命中)
// 清空缓存并重新获取数据
userCache.resetCache();
System.out.println(userCache.getValue("1")); // 输出:Alice (重新加载)
}
}
从外部数据源加载数据,key: 1
Alice
从外部数据源加载数据,key: 2
Bob
从外部数据源加载数据,key: 4
Unknown User
Alice
缓存已清空并重置
从外部数据源加载数据,key: 1
Alice
在 pom.xml
中添加以下依赖即可使用 Guava 和日志功能:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。