緣起
看了官方的關于Guava Cache的介紹,感覺太過于啰嗦,我個人是很不喜歡,看了好大半天也看不懂,直到翻到了一篇國内的文章才看懂,特此記錄,以備查閱。
如何使用Cache
Cache<String,String> cache = CacheBuilder.newBuilder().build();
public void test() {
cache.put("word","Hello Guava Cache");
System.out.println(cache.getIfPresent("word"));
}
看到Cache非常類似于JDK中的Map,但是相比于Map,Guava Cache提供了很多更強大的功能。
自動加載
Cache的get方法有兩個參數,第一個參數是要從Cache中擷取記錄的key,第二個記錄是一個Callable對象。當緩存中已經存在key對應的記錄時,get方法直接傳回key對應的記錄。如果緩存中不包含key對應的記錄,Guava會啟動一個線程執行Callable對象中的call方法,call方法的傳回值會作為key對應的值被存儲到緩存中,并且被get方法傳回。Guava可以保證當有多個線程同時通路Cache中的一個key時,如果key對應的記錄不存在,Guava隻會啟動一個線程執行get方法中Callable參數對應的任務加載資料存到緩存。當加載完資料後,任何線程中的get方法都會擷取到key對應的值。
String value = cache.get("key", new Callable<String>() {
public String call() throws Exception {
System.out.println("load1"); //加載資料線程執行标志
Thread.sleep(1000); //模拟加載時間
return "auto load by Callable";
}
});
設定最大存儲
Cache<String,String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
.build();
cache.put("key1","value1");
cache.put("key2","value2");
cache.put("key3","value3");
System.out.println("第一個值:" + cache.getIfPresent("key1"));
System.out.println("第二個值:" + cache.getIfPresent("key2"));
System.out.println("第三個值:" + cache.getIfPresent("key3"));
設定過期時間
在建構Cache對象時,可以通過CacheBuilder類的expireAfterAccess和expireAfterWrite兩個方法為緩存中的對象指定過期時間,過期的對象将會被緩存自動删除。其中,expireAfterWrite方法指定對象被寫入到緩存後多久過期,expireAfterAccess指定對象多久沒有被通路後過期。
Cache<String,String> cache = CacheBuilder.newBuilder()
.maximumSize(2)
.expireAfterWrite(3,TimeUnit.SECONDS)
.build();
弱引用
可以通過weakKeys和weakValues方法指定Cache隻儲存對緩存記錄key和value的弱引用。這樣當沒有其他強引用指向key和value時,key和value對象就會被垃圾回收器回收。
Cache<String,Object> cache = CacheBuilder.newBuilder()
.maximumSize(2)
.weakValues()
.build();
顯示清除
可以調用Cache的invalidateAll或invalidate方法顯示删除Cache中的記錄。invalidate方法一次隻能删除Cache中一個記錄,接收的參數是要删除記錄的key。invalidateAll方法可以批量删除Cache中的記錄,當沒有傳任何參數時,invalidateAll方法将清除Cache中的全部記錄。invalidateAll也可以接收一個Iterable類型的參數,參數中包含要删除記錄的所有key值。
Cache<String,String> cache = CacheBuilder.newBuilder().build();
Object value = new Object();
cache.put("key1","value1");
cache.put("key2","value2");
cache.put("key3","value3");
List<String> list = new ArrayList<String>();
list.add("key1");
list.add("key2");
cache.invalidateAll(list);//批量清除list中全部key對應的記錄
監聽器監聽移除元素動作
可以為Cache對象添加一個移除監聽器,這樣當有記錄被删除時可以感覺到這個事件。
RemovalListener<String, String> listener = new RemovalListener<String, String>() {
public void onRemoval(RemovalNotification<String, String> notification) {
System.out.println("[" + notification.getKey() + ":" + notification.getValue() + "] is removed!");
}
};
Cache<String,String> cache = CacheBuilder.newBuilder()
.maximumSize(3)
.removalListener(listener)
.build();
統計資訊
可以對Cache的命中率、加載資料時間等資訊進行統計。在建構Cache對象時,可以通過CacheBuilder的recordStats方法開啟統計資訊的開關。開關開啟後Cache會自動對緩存的各種操作進行統計,調用Cache的stats方法可以檢視統計後的資訊。
Cache<String,String> cache = CacheBuilder.newBuilder()
.maximumSize(3)
.recordStats() //開啟統計資訊開關
.build();
System.out.println(cache.stats()); //擷取統計資訊

LoadingCache
LoadingCache的使用
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.build(
new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
//在這裡可以初始化加載資料的緩存資訊,讀取資料庫中資訊或者是加載檔案中的某些資料資訊
return "";
}
});
CacheLoader<String, String> loader = new CacheLoader<String, String> () {
public String load(String key) throws Exception {
Thread.sleep(1000); //休眠1s,模拟加載資料
System.out.println(key + " is loaded from a cacheLoader!");
return key + "'s value";
}
};
LoadingCache<String,String> loadingCache = CacheBuilder.newBuilder()
.maximumSize(3)
.build(loader);//在建構時指定自動加載器
@Bean
public LoadingCache<String, Object> myCacheStorage() {
return CacheBuilder.newBuilder()
.build(new CacheLoader<String, Object>() {
@Override
public Object load(String name) throws Exception {
//在這裡可以初始化加載資料的緩存資訊,讀取資料庫中資訊或者是加載檔案中的某些資料資訊
return null;
}
});
}
@Autowired
LoadingCache<String, Object> loadingCache;