背景
LoadingCache是GuavaCache構建緩存實體的方法,是一個支持多線程並發讀寫、高性能、通用的in-heap(堆)本地緩存。
支持key不存在時按照給定的CacheLoader 的loader方法進行loading。如果有多個線程同時get一個不存在的key,那么會有一個線程負責load,其他線程阻塞wait等待。
CacheBuilder方法參數
- maximumSize(): 最大緩存上限,快達到上限或達到上限,處理了時間最長沒被訪問過的對象或者根據配置的被釋放的對象
- expireAfterAccess():設置時間對象沒有被讀/寫訪問則對象從內存中刪除,回收順序和基於大小回收一樣
- expireAfterWrite(): 設置時間對象沒有被寫訪問則對象從內存中刪除
- refreshAfterWrite():為緩存增加自動定時刷新功能。緩存項只有在被檢索時才會真正刷新,即只有刷新間隔時間到了再去get(key)才會重新去執行Loading,否則就算刷新間隔時間到了也不會執行loading操作。
CacheLoader
實現自動加載緩存。可以在其中自定義load方法和reload方法,根據需求加載緩存和刷新緩存。
Cache常用方法
- get(key): 有值則返回緩存值,沒有則執行load方法加載緩存。
- put(key, value): 顯式地向緩存中插入值,會直接覆蓋掉已有鍵之前映射的值。
- invalidate(key): 顯式地清除個別緩存項。
- invalidateAll(keys): 批量清除緩存項。
- invalidateAll(): 清除所有緩存項。
- refresh(key): (異步)主動刷新對應緩存值 。在刷新操作進行時,緩存仍然可以向其他線程返回舊值。
實例
@Slf4j
@Component
public class EntryCache {
@Autowired
EntryMapper entryMapper;
/**
* guava cache 緩存實體
*/
LoadingCache<String, Entry> cache = CacheBuilder.newBuilder()
// 緩存刷新時間
.refreshAfterWrite(10, TimeUnit.MINUTES)
// 設置緩存個數
.maximumSize(500)
.build(new CacheLoader<String, Entry>() {
@Override
// 當本地緩存命沒有中時,調用load方法獲取結果並將結果緩存
public Entry load(String appKey) {
return getEntryFromDB(appKey);
}
// 數據庫進行查詢
private Entry getEntryFromDB(String name) {
log.info("load entry info from db!entry:{}", name);
return entryMapper.selectByName(name);
}
});
/**
* 對外暴露的方法
* 從緩存中取entry,沒取到就走數據庫
*/
public Entry getEntry(String name) throws ExecutionException {
return cache.get(name);
}
@PostConstruct
public void initCache() {
log.info("init entry cache start!");
//讀取所有記錄
List<Entry> list = entryMapper.selectAll();
if (CollectionUtils.isEmpty(list)) {
return;
}
for (Entry entry : list) {
try {
this.getEntry(entry.getName());
} catch (Exception e) {
log.error("init cache error!,e:{}", e.getMessage());
}
}
log.info("init entry cache end!");
}
}