一、引入依赖
<!--caffeine--><dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId></dependency>
Caffeine提供手动加载、自动加载、异步手动加载、异步自动加载四种缓存策略。
二、手动加载时间参数:
expireAfterWrite:基于写入时间。
expireAfterAccess: 基于访问时间。
expireAfter: 有效期可根据读更新写入进行调整。
权重参数:
maximumWeight: 基于权重的容量策略,缓存中的元素主要用于不同的权重场景。
maximumSize: 基于容量策略,当缓存中的元素数量超过时,基于就近度和频率的算法驱逐不再使用的元素。
查询缓存&添加缓存:
asMap: 获取所有缓存数据。
getIfPresent(key): 如果有这个key的缓存数据,请返回,如果没有,请返回null。
get(key,(key)->{缓存初始化}: 若指定key缓存不存在,则设置缓存初始化数据并返回。
添加缓存:
put(key,value): 添加缓存。
清空缓存:
invalidate(key): 移除指定key的缓存。
invalidateAll: 移除所有缓存。
接下来,我们将创建一个测试类别进行测试
import com.github.benmanes.caffeine.cache.Cache;import com.github.benmanes.caffeine.cache.Caffeine;import org.checkerframework.checker.nullness.qual.NonNull;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest; import java.util.concurrent.ConcurrentMap;import java.util.concurrent.TimeUnit; /** * @author qinxun * @date 2023-06-05 * @Descripion: 使用caffeine */@SpringBootTestpublic class CacheTest { /** * 手动加载 */ @Test void test1() throws InterruptedException { Cache<Object, Object> cache = Caffeine.newBuilder() // 设置写入2分钟后失效 .expireAfterWrite(2, TimeUnit.MINUTES) // 设置最大缓存量 .maximumSize(50) .build(); // getIfPresent:获取指定key的数据 没有返回null Object id = cache.getIfPresent("id"); System.out.println(id); // get: 如果数据不存在,则使用lambda表达式返回的数据设置缓存 并返回缓存数据 Object obj = cache.get("id", (e) -> 10); System.out.println(obj); // put: 添加缓存 cache.put("id", 20); Object obj1 = cache.getIfPresent("id"); System.out.println(obj1); // put:添加缓存 cache.put("name", "qq"); // asMap: 获取所有缓存数据 ConcurrentMap<@NonNull Object, @NonNull Object> map = cache.asMap(); System.out.println(map); // invalidate: 移除指定的key缓存 cache.invalidate("name"); ConcurrentMap<@NonNull Object, @NonNull Object> map1 = cache.asMap(); System.out.println(map1); // invalidateAll: 移除所有缓存 cache.invalidateAll(); ConcurrentMap<@NonNull Object, @NonNull Object> map2 = cache.asMap(); System.out.println(map2); }}
试验结果如下:
null1020{name=qq, id=20}{id=20}{}
三、自动加载自动加载是利用自动加载的缓存数据获取缓存,缓存不存在。
/** * 自动加载 */ @Test void test2(){ AtomicInteger atomicInteger = new AtomicInteger(1); LoadingCache<String, Integer> cache = Caffeine.newBuilder() // 设置数据写入2分钟后过期 .expireAfterWrite(2, TimeUnit.MINUTES) // 设置最大缓存量 .maximumSize(50) .build(new CacheLoader<String, Integer>() { @Override public @Nullable Integer load(@NonNull String s) throws Exception { // 如果没有缓存数据 返回自动加载的数据 return atomicInteger.get(); } }); // get:如果没有缓存数据 使用自动加载的数据 Integer data1 = cache.get("id"); System.out.println(data1); cache.put("age",2); //getAll:类似于get 如果缓存key不存在,默认数据将自动加载 否则,返回缓存数据 List<String> keyList = Lists.newArrayList("id","age"); Map<@NonNull String, @NonNull Integer> map = cache.getAll(keyList); System.out.println(map); }
试验结果如下:
1{id=1, age=2}
四、手动加载异步getIfPresent(key): 存在时返回CompletableFuture,不存在时返回null,因此注意npe的问题。
get(key, Function<>): 如果没有获得第一个key缓存数据,则第二个参数表示加载数据的逻辑。
put(key, CompletableFuture<>): 手动添加缓存,请注意,这里没有直接添加特定的value到缓存。
synchronous().invalidate() : 缓存同步清除。
getAll: 一次获得多个缓存,同样是在缓存中取缓存,不在的根据第二个传参加载。
/** * 手动加载异步 */ @Test void test3() throws ExecutionException, InterruptedException { AsyncCache<Object, Object> asyncCache = Caffeine.newBuilder() .expireAfterWrite(2, TimeUnit.MINUTES) .maximumSize(50) .buildAsync(); // getIfPresent(key): 如果不存在,就返回nulllll CompletableFuture<Object> idData = asyncCache.getIfPresent("id"); System.out.println(idData); //get(key,(key)->{}):第二个参数字表示当它不存在时,初始化并写入缓存 CompletableFuture<Object> iddata2 = asyncCache.get("id", (key) -> 5); System.out.println(iddata2.get()); //put(key,CompletableFuture): 手动写入缓存 asyncCache.put("id", CompletableFuture.supplyAsync(() -> 10)); //asMap:返回所有缓存数据 ConcurrentMap<@NonNull Object, @NonNull CompletableFuture<Object>> map = asyncCache.asMap(); for (Map.Entry<Object, CompletableFuture<Object>> entry : map.entrySet()) { System.out.println(entry.getKey() + "==>" + entry.getValue().get()); } //synchronous().invalidate(key): 移除缓存 asyncCache.synchronous().invalidate("id"); asyncCache.put("age", CompletableFuture.supplyAsync(() -> 20)); ConcurrentMap<@NonNull Object, @NonNull CompletableFuture<Object>> map1 = asyncCache.asMap(); for (Map.Entry<Object, CompletableFuture<Object>> entry : map1.entrySet()) { System.out.println(entry.getKey() + "==>" + entry.getValue().get()); } }
试验结果如下:
null5id==>10age==>20
五、异步自动加载类似于异步手动加载,但也增加了自动加载策略。
/** * 自动加载异步 */ @Test void test4() throws ExecutionException, InterruptedException { AtomicInteger atomicInteger = new AtomicInteger(5); AsyncLoadingCache<String, Integer> asyncLoadingCache = Caffeine.newBuilder() .expireAfterWrite(2, TimeUnit.MINUTES) .maximumSize(50) .buildAsync(new CacheLoader<String, Integer>() { @Override public @Nullable Integer load(@NonNull String s) throws Exception { // 当缓存不存在时 该数据自动加载 return atomicInteger.get(); } }); //getIfPresent(key): 如果不存在,就返回nulllll CompletableFuture<Integer> idData = asyncLoadingCache.getIfPresent("id"); System.out.println(idData); // get(key): 当缓存不存在时,使用自动加载的数据 CompletableFuture<Integer> iddata2 = asyncLoadingCache.get("id"); System.out.println(iddata2.get()); // put:手动添加缓存 asyncLoadingCache.put("age", CompletableFuture.supplyAsync(() -> 20)); //asMap:返回所有缓存数据 ConcurrentMap<@NonNull String, @NonNull CompletableFuture<Integer>> map = asyncLoadingCache.asMap(); for (Map.Entry<String, CompletableFuture<Integer>> entry : map.entrySet()) { System.out.println(entry.getKey() + "==>" + entry.getValue().get()); } // synchronous().invalidateAll(): 移除所有缓存 asyncLoadingCache.synchronous().invalidateAll(); CompletableFuture<Integer> ageData = asyncLoadingCache.getIfPresent("age"); System.out.println(ageData); }
试验结果如下:
null5id==>5age==>20null