Spring內(nèi)存緩存Caffeine的基本使用教程分享
項目配置
依賴
首先搭建一個標(biāo)準(zhǔn)的SpringBoot項目工程,相關(guān)版本以及依賴如下
本項目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA進(jìn)行開發(fā)
<dependencies>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
使用實例
引入上面的jar包之后,就可以進(jìn)入caffeine的使用環(huán)節(jié)了;我們主要依照官方wiki來進(jìn)行演練
Home zh CN · ben-manes/caffeine Wiki
caffeine提供了四種緩存策略,主要是基于手動添加/自動添加,同步/異步來進(jìn)行區(qū)分
其基本使用姿勢于Guava差不多
1.手動加載
private LoadingCache<String, Integer> autoCache;
private AtomicInteger idGen;
public CacheService() {
// 手動緩存加載方式
idGen = new AtomicInteger(100);
uidCache = Caffeine.newBuilder()
// 設(shè)置寫入后五分鐘失效
.expireAfterWrite(5, TimeUnit.MINUTES)
// 設(shè)置最多的緩存數(shù)量
.maximumSize(100)
.build();
}1.1 三種失效策略
注意參數(shù)設(shè)置,我們先看一下失效策略,共有下面幾種
權(quán)重:
- maximumSize: 基于容量策略,當(dāng)緩存內(nèi)元素個數(shù)超過時,通過基于就近度和頻率的算法來驅(qū)逐掉不會再被使用到的元素
- maximumWeight: 基于權(quán)重的容量策略,主要應(yīng)用于緩存中的元素存在不同的權(quán)重場景
時間:
- expireAfterAccess: 基于訪問時間
- expireAfterWrite: 基于寫入時間
- expireAfter: 可以根據(jù)讀更新寫入來調(diào)整有效期
引用:
- weakKeys: 保存的key為弱引用
- weakValues: 保存的value會使用弱引用
- softValues: 保存的value使用軟引用
弱引用:這允許在GC的過程中,當(dāng)沒有被任何強引用指向的時候去將緩存元素回收
軟引用:在GC過程中被軟引用的對象將會被通過LRU算法回收
1.2 緩存增刪查姿勢
接下來我們看一下手動方式的使用
public void getUid(String session) {
// 重新再取一次,這次應(yīng)該就不是重新初始化了
Integer uid = uidCache.getIfPresent(session);
System.out.println("查看緩存! 當(dāng)沒有的時候返回的是 uid: " + uid);
// 第二個參數(shù)表示當(dāng)不存在時,初始化一個,并寫入緩存中
uid = uidCache.get(session, (key) -> 10);
System.out.println("初始化一個之后,返回的是: " + uid);
// 移除緩存
uidCache.invalidate(session);
// 手動添加一個緩存
uidCache.put(session + "_2", 11);
// 查看所有的額緩存
Map map = uidCache.asMap();
System.out.println("total: " + map);
// 干掉所有的緩存
uidCache.invalidateAll();
}查詢緩存&添加緩存
getIfPresent(key): 不存在時,返回nullget(key, (key) -> {value初始化策略}): 不存在時,會根據(jù)第二個lambda表達(dá)式來寫入數(shù)據(jù),這個就表示的是手動加載緩存asMap: 獲取緩存所有數(shù)據(jù)
添加緩存
put(key, val): 主動添加緩存
清空緩存
invalidate: 主動移除緩存invalidateAll: 失效所有緩存
執(zhí)行完畢之后,輸出日志:
查看緩存! 當(dāng)沒有的時候返回的是 uid: null
初始化一個之后,返回的是: 10
total: {02228476-bcd9-412d-b437-bf0092c4a5f6_2=11}
2.自動加載
在創(chuàng)建的時候,就指定緩存未命中時的加載規(guī)則
// 在創(chuàng)建時,自動指定加載規(guī)則
private LoadingCache<String, Integer> autoCache;
private AtomicInteger idGen;
public CacheService() {
// 手動緩存加載方式
idGen = new AtomicInteger(100);
autoCache = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(100)
.build(new CacheLoader<String, Integer>() {
@Override
public @Nullable Integer load(@NonNull String key) throws Exception {
return idGen.getAndAdd(1);
}
});
}它的配置,與前面介紹的一致;主要的區(qū)別點在于build時,確定緩存值的獲取方式
2.1 緩存使用姿勢
public void autoGetUid(String session) {
Integer uid = autoCache.getIfPresent(session);
System.out.println("自動加載,沒有時返回: " + uid);
uid = autoCache.get(session);
System.out.println("自動加載,沒有時自動加載一個: " + uid);
// 批量查詢
List<String> keys = Arrays.asList(session, session + "_1");
Map<String, Integer> map = autoCache.getAll(keys);
System.out.println("批量獲取,一個存在一個不存在時:" + map);
// 手動加一個
autoCache.put(session + "_2", 11);
Map total = autoCache.asMap();
System.out.println("total: " + total);
}與前面的區(qū)別在于獲取緩存值的方式
- get(key): 不用傳第二個參數(shù),直接傳key獲取對應(yīng)的緩存值,如果沒有自動加載數(shù)據(jù)
- getAll(keys): 可以批量獲取數(shù)據(jù),若某個key不再緩存中,會自動加載;在里面的則直接使用緩存的
實際輸出結(jié)果如下
自動加載,沒有時返回: null
自動加載,沒有時自動加載一個: 100
批量獲取,一個存在一個不存在時:{02228476-bcd9-412d-b437-bf0092c4a5f6=100, 02228476-bcd9-412d-b437-bf0092c4a5f6_1=101}
total: {02228476-bcd9-412d-b437-bf0092c4a5f6_2=11, 02228476-bcd9-412d-b437-bf0092c4a5f6_1=101, 02228476-bcd9-412d-b437-bf0092c4a5f6=100}
3.異步手動加載
異步,主要是值在獲取換粗內(nèi)容時,采用的異步策略;使用與前面沒有什么太大差別
// 手動異步加載緩存
private AsyncCache<String, Integer> asyncUidCache;
public CacheService() {
asyncUidCache = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(100)
.buildAsync();
}3.1 緩存使用姿勢
public void asyncGetUid(String session) throws ExecutionException, InterruptedException {
// 重新再取一次,這次應(yīng)該就不是重新初始化了
CompletableFuture<Integer> uid = asyncUidCache.getIfPresent(session);
System.out.println("查看緩存! 當(dāng)沒有的時候返回的是 uid: " + (uid == null ? "null" : uid.get()));
// 第二個參數(shù)表示當(dāng)不存在時,初始化一個,并寫入緩存中
uid = asyncUidCache.get(session, (key) -> 10);
System.out.println("初始化一個之后,返回的是: " + uid.get());
// 手動塞入一個緩存
asyncUidCache.put(session + "_2", CompletableFuture.supplyAsync(() -> 12));
// 移除緩存
asyncUidCache.synchronous().invalidate(session);
// 查看所有的額緩存
System.out.println("print total cache:");
for (Map.Entry<String, CompletableFuture<Integer>> sub : asyncUidCache.asMap().entrySet()) {
System.out.println(sub.getKey() + "==>" + sub.getValue().get());
}
System.out.println("total over");
}- getIfPresent: 存在時返回CompletableFuture,不存在時返回null,因此注意npe的問題
- get(key, Function<>): 第二個參數(shù)表示加載數(shù)據(jù)的邏輯
- put(key, CompletableFuture<>): 手動加入緩存,注意這里也不是直接加一個具體的value到緩存
- synchronous().invalidate() : 同步清除緩存
- getAll: 一次獲取多個緩存,同樣的是在緩存的取緩存,不在的根據(jù)第二個傳參進(jìn)行加載
與前面相比,使用姿勢差不多,唯一注意的是,獲取的并不是直接的結(jié)果,而是CompletableFuture,上面執(zhí)行之后的輸出如下:
查看緩存! 當(dāng)沒有的時候返回的是 uid: null
初始化一個之后,返回的是: 10
print total cache:
5dd53310-aec7-42a5-957e-f7492719c29d_2==>12
total over
4.異步自動加載
在定義緩存時,就指定了緩存不存在的加載邏輯;與第二個相比區(qū)別在于這里是異步加載數(shù)據(jù)到緩存中
private AtomicInteger idGen;
// 自動異步加載緩存
private AsyncLoadingCache<String, Integer> asyncAutoCache;
public CacheService() {
idGen = new AtomicInteger(100);
asyncAutoCache = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(100)
.buildAsync(new CacheLoader<String, Integer>() {
@Override
public @Nullable Integer load(@NonNull String key) throws Exception {
return idGen.getAndAdd(1);
}
});
}4.1 緩存使用姿勢
public void asyncAutoGetUid(String session) {
try {
CompletableFuture<Integer> uid = asyncAutoCache.getIfPresent(session);
System.out.println("自動加載,沒有時返回: " + (uid == null ? "null" : uid.get()));
uid = asyncAutoCache.get(session);
System.out.println("自動加載,沒有時自動加載一個: " + uid.get());
// 批量查詢
List<String> keys = Arrays.asList(session, session + "_1");
CompletableFuture<Map<String, Integer>> map = asyncAutoCache.getAll(keys);
System.out.println("批量獲取,一個存在一個不存在時:" + map.get());
// 手動加一個
asyncAutoCache.put(session + "_2", CompletableFuture.supplyAsync(() -> 11));
// 查看所有的額緩存
System.out.println("print total cache:");
for (Map.Entry<String, CompletableFuture<Integer>> sub : asyncAutoCache.asMap().entrySet()) {
System.out.println(sub.getKey() + "==>" + sub.getValue().get());
}
System.out.println("total over");
// 清空所有緩存
asyncAutoCache.synchronous().invalidateAll();
} catch (Exception e) {
e.printStackTrace();
}
}輸出:
自動加載,沒有時返回: null
自動加載,沒有時自動加載一個: 102
批量獲取,一個存在一個不存在時:{5dd53310-aec7-42a5-957e-f7492719c29d=102, 5dd53310-aec7-42a5-957e-f7492719c29d_1=103}
print total cache:
5dd53310-aec7-42a5-957e-f7492719c29d_2==>11
5dd53310-aec7-42a5-957e-f7492719c29d_1==>103
5dd53310-aec7-42a5-957e-f7492719c29d==>102
total over
以上就是Spring內(nèi)存緩存Caffeine的基本使用教程分享的詳細(xì)內(nèi)容,更多關(guān)于Spring內(nèi)存緩存Caffeine的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java 詳解單向加密--MD5、SHA和HMAC及簡單實現(xiàn)實例
這篇文章主要介紹了Java 詳解單向加密--MD5、SHA和HMAC及簡單實現(xiàn)實例的相關(guān)資料,需要的朋友可以參考下2017-02-02
淺談SpringBoot項目如何讓前端開發(fā)提高效率(小技巧)
這篇文章主要介紹了淺談SpringBoot項目如何讓前端開發(fā)提高效率(小技巧),主要介紹了Swagger和Nginx提高效率的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04
Spring boot定時任務(wù)的原理及動態(tài)創(chuàng)建詳解
這篇文章主要給大家介紹了關(guān)于Spring boot定時任務(wù)的原理及動態(tài)創(chuàng)建的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
Spring Boot集成教程之異步調(diào)用Async
在項目中,當(dāng)訪問其他人的接口較慢或者做耗時任務(wù)時,不想程序一直卡在耗時任務(wù)上,想程序能夠并行執(zhí)行,我們可以使用多線程來并行的處理任務(wù),也可以使用spring提供的異步處理方式@Async。需要的朋友們下面來一起看看吧。2018-03-03
Springboot項目中定時任務(wù)的四種實現(xiàn)方式詳解
Spring的@Scheduled注解是一種非常簡單和便捷的實現(xiàn)定時任務(wù)的方式,通過在方法上添加@Scheduled注解,我們可以指定方法在特定的時間間隔或固定的時間點執(zhí)行,本文給大家介紹Springboot項目中定時任務(wù)的四種實現(xiàn)方式,感興趣的的朋友一起看看b2024-02-02

