最近換到了新公司,又開始使用一些從沒有使用過的技術,也有使用一些舊技術…其中的甘苦談就不提了,
今天要來分享一個最近使用到的java套件 :google guava: cache
google guava是google分享的一個java套件,
可以有大量的神奇的功能,其中有不少非常實用且容易上手
今天要介紹的Cache則是其中之一。
他有點像是ConcureentHashMap ,只是再加上了時間變數
(以下的介紹會以讀者都知道什麼是ConcureentHashMap 來說明)
主要的作用就是讓超過時間的物件可以自動從map中移除,因此用Cache稱乎它確實非常洽當。
詳細的Code介紹:
最快的寫法:
CacheLoader<String, String> loader = new CacheLoader<String, String>() { LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(loader); |
只需要把xxxxx implement完就可以了。
這一段code,其實就是等於建造了一個ConcurrenctHashMap<String, String>();
不同的是你不需要事先把key, value放入。
每一次,當你從cache.get(key) 的時候,當他找不到物件,他會自動的去load去抓取value,並且將資料存入cache裡面去。
尤於不是一開始全部輸入,所以其實像是個lazyload 的hashmap
使用上當比一般的hashMap省空間一些。
-----------------------------------------------------------------------------------------------------------------------
但我剛剛說了,這是一個cache, lazyload並不能夠稱為 cache,
因此一般我們會至少加上一個expire的變數。
一般會使用 .expireAfterAccess,或是.expireAfterWrite 兩種方法
(P.S. 剛剛看了文件,其實還有refreshAfterAcess, refreshAfterWrite,適用於資料會一直變動的方式, 在這裡先不討論)
expireAfterAccess 是指最後一次Access之後多久會失效 (有點像是LRU Least Recently Used)
expireAfterWrite則是指放入map後多久會失效 (FIFO, first in, first out)
最後,還有一個變數:既然是Cache,那麼作戲要作全套,cache 是有空間限制的,因此也可以加上size
.maximumSize(200)
因此,如果把整段時間寫出來的話,大概就會變成:
CacheLoader<String, String> loader = new CacheLoader<String, String>() { LoadingCache<String, String> cache = CacheBuilder.newBuilder() |
xxxxx還是要自己寫,
expire的時間可以用分鐘,也可以用小時,或是秒,視個人需求而加入。
本來自己使用的需求到這裡就結束了。
但是其實還有一個很常用的removeListener,就一起打出來
Listener主要是在某個key/value要被移除的時候會被觸發
(網路上的說明都只有在那邊記錄log,但其實如果這些cache會存到DB的話,也可以在removal的時候將資料存到DB裡面)
先宣告一個RemoveListener
RemovalListener<String, String> listener = |
然後將之放進去我們需要的cache裡面即可。
所以整段code會再度變成( 其實也只是多了一行)
CacheLoader<String, String> loader = new CacheLoader<String, String>() {
RemovalListener<String, String> listener =
|
Guava真的是一個很好用的api,比起我同時在研究的shiro,這個真的簡單易懂多了。
更多的功能介紹可以看一下guava cache的介紹投影片:
介紹投影片:
http://guava-libraries.googlecode.com/files/JavaCachingwithGuava.pdf
要注意的問題:
1: NoSuchMethodException : assertNotNull
這是一個莫名其妙的bug,後來找了很久,發現是因為多灌了一個google-collection 的jar檔,移除後就沒事了
至於為什麼,我到現在還是不知道為什麼,個人覺得可能是namespace相衝,使得method名稱重複的問題導致。
但又覺得google不大可能犯這種錯誤,所以……
2: guava之中非常不愛null,所以盡可能的不要直接回傳null,如果在loader回傳null,他會傳出Exception,而且下一次還是會再來嘗試一次。
我自己的作法是定義一個DEFAULT_VALUE, 如果找不到就回傳該變數,詳情可以參考
https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained
我自己的寫法: ( 以下不是在COMPILER打的,只是隨便打一個範例而已)
Public static final EMPTY_VALUE = ""; private String xxxxx(String key){ String ret = loadDB(key); if (ret==null) return EMPTY_VALUE; return ret; }
|
這樣子然後自己處理資料的時候,只要記得要另外處理"" (空字串)就可以了
而且很多時候空字串就讓它空著沒有關係。會節省很多時間。
如果value不是字串,而是自定的class,也可以用類似的方法來處理。
3: 自己試用的時候,如果有設maximum size的時候,如果該size尚未用完,他不會主動移掉cache.
所以不只是lazyload,而且還是lazyRemove。這點也要特別注意。
沒有留言:
張貼留言