基于Caffeine自定义接口实现本地缓存
一、简介
caffeine是基于java8,Guava开发的一款高性能的本地缓存,是现场安全的本地缓存,可以用于多个场景:
1.用于用户重复提交数据验证
2.缓存数据
3.解决之前缓存的限制大小,导致OOM
4.通过设置时间解决内存占用资源浪费
5.防止api接口重复调用风险--性能提升
二、实战
1.添加依赖
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.9.2</version>
</dependency>
2.定义自定义接口
package com.test.utils.caffeine;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
/**
* Caffeine封装接口
*/
public interface CaffeineCache<K, V> {
/**
* put
*
* @param key
* @param value
*/
void put(K key, V value);
/**
* get
*
* @param key
* @return
*/
V get(K key);
/**
* 判断是否包含K
*
* @param key
* @return
*/
boolean containsKey(K key);
/**
* 判断是否包含V
*
* @param value
* @return
*/
boolean containsValue(V value);
/**
* 移除某个K
*
* @param key
*/
void remove(Object key);
/**
* 查询缓存命中,驱逐等数量
*
* @return
*/
CacheStats cacheStats();
/**
* 清除全部(性能较慢,考虑场景使用)
*/
void clear();
/**
* 转成MAP
*
* @return
*/
ConcurrentMap<K, V> asMap();
/**
* 获取values
*
* @return
*/
Collection<V> values();
/**
* 获取缓存大小
*
* @return
*/
long size();
/**
* 主动回收已失效的缓存
*
* @return
*/
void cleanUp();
/**
* 当缓存中有这个key就使用key对应的value值 如果没有就使用默认的value
*
* @return
*/
V getOrDefault(K k, V v);
/**
* entrySet
*
* @return
*/
Set<Map.Entry<K, V>> entrySet();
}
2.自定义接口实现类
package com.test.utils.caffeine;
import com.github.benmanes.caffeine.cache.*;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
/**
* Caffeine封装API实现类
*/
@Slf4j
public class CaffeineCacheLocal<K, V> implements CaffeineCache<K, V> {
private final Cache<K, V> localCache;
private RemovalListener<? super K, ? super V> removalListener;
private long maximumSize = -1L;
private long duration = -1L;
private TimeUnit unit;
public CaffeineCacheLocal() {
localCache = initCache();
}
public CaffeineCacheLocal(RemovalListener<? super K, ? super V> removalListener, long maximumSize, long duration, TimeUnit unit) {
if (removalListener != null) {
this.removalListener = removalListener;
}
if (unit != null) {
this.unit = unit;
}
this.duration = duration;
this.maximumSize = maximumSize;
this.localCache = initCache();
}
/**
* 初始化
*
* @return
*/
private Cache<K, V> initCache() {
Caffeine<Object, Object> caffeine = Caffeine.newBuilder();
//暂时未加入权重逻辑 所以maximumSize必须设定
//若加入权重逻辑后,可以根据是否有权重判断处理
if (this.maximumSize <= 0L) {
throw new RuntimeException("maximumSize is must be set");
}
//key的最大size
caffeine.maximumSize(this.maximumSize);
//expireAfterWrite全局时间淘汰策略
if (this.duration > 0L && this.unit != null) {
caffeine.expireAfterWrite(this.duration, this.unit);
}
//开启淘汰监听
if (this.removalListener != null) {
caffeine.removalListener(this.removalListener);
}
return caffeine.build();
}
@Override
public void put(K key, final V value) {
localCache.put(key, value);
}
@Override
public V get(K key) {
if (Objects.nonNull(key)){
return localCache.getIfPresent(key);
}
return null;
}
@Override
public boolean containsKey(K key) {
return asMap().containsKey(key);
}
@Override
public boolean containsValue(V value) {
return asMap().containsValue(value);
}
@Override
public void remove(Object key) {
localCache.invalidate(key);
}
@Override
public CacheStats cacheStats() {
return localCache.stats();
}
@Override
public void clear() {
localCache.invalidateAll();
}
@Override
public ConcurrentMap<K, V> asMap() {
return localCache.asMap();
}
@Override
public Collection<V> values() {
return asMap().values();
}
@Override
public long size() {
return localCache.estimatedSize();
}
@Override
public void cleanUp() {
localCache.cleanUp();
}
@Override
public V getOrDefault(K k, V defaultValue) {
V v;
return ((v = get(k)) != null) ? v : defaultValue;
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
return asMap().entrySet();
}
public static Builder<Object, Object> newBuilder() {
return new Builder<>();
}
public static class Builder<K1, V1> {
private RemovalListener<? super K1, ? super V1> removalListener;
private long maximumSize;
private long duration;
private TimeUnit unit;
public Builder<K1, V1> removalListener(RemovalListener removalListener) {
this.removalListener = removalListener;
return this;
}
public Builder<K1, V1> maximumSize(long maximumSize) {
this.maximumSize = maximumSize;
return this;
}
public Builder<K1, V1> expireAfterWrite(long duration, TimeUnit unit) {
this.duration = duration;
this.unit = unit;
return this;
}
public <K extends K1, V extends V1> CaffeineCache<K, V> build() {
return new CaffeineCacheLocal<>(removalListener, maximumSize, duration, unit);
}
}
}
三、测试结果
public void expireAfterWriteTest() {
CaffeineCache<Long, Set<String>> caffeineCache = CaffeineCacheLocal.newBuilder()
.maximumSize(100)
.expireAfterWrite(5, TimeUnit.SECONDS)
.removalListener(new RemovalListener<Long, Set<String>>() {
@Override
public void onRemoval(@Nullable Long key, @Nullable Set<String> value, @NonNull RemovalCause removalCause) {
System.out.println("移除了key:" + key + " value:" + value + " cause:" + removalCause);
}
})
.build();
caffeineCache.put(1L, Sets.newHashSet("1", "2"));
caffeineCache.put(2L, Sets.newHashSet("3", "4"));
System.out.println(caffeineCache.get(2L));
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(caffeineCache.get(2L));
}
原文链接:https://blog.csdn.net/weixin_39382426/article/details/131392031
分类:
本地缓存
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)