阿里开源 JetCache 缓存框架介绍使用
一、JetCache
JetCache是一個基于Java的緩存系統封裝,提供統一的API和注解來簡化緩存的使用。 JetCache提供了比SpringCache更加強大的注解,可以原生的支持TTL、兩級緩存、分布式自動刷新,還提供了Cache接口用于手工緩存操作。 當前有四個實現,RedisCache、TairCache(此部分未在github開源)、CaffeineCache(in memory)和一個簡易的LinkedHashMapCache(in memory),要添加新的實現也是非常簡單的。
全部特性:
- 通過統一的API訪問Cache系統
- 通過注解實現聲明式的方法緩存,支持TTL和兩級緩存
- 通過注解創建并配置Cache實例
- 針對所有Cache實例和方法緩存的自動統計
- Key的生成策略和Value的序列化策略是可以配置的
- 分布式緩存自動刷新,分布式鎖 (2.2+)
- 異步Cache API (2.2+,使用Redis的lettuce客戶端時)
- Spring Boot支持
github地址: https://github.com/alibaba/jetcache
注意:
JetCache需要JDK1.8、Spring Framework4.0.8以上版本。Spring Boot為可選,需要1.1.9以上版本。如果不使用注解(僅使用jetcache-core),Spring Framework也是可選的,此時使用方式與Guava/Caffeine cache類似。
二、SpringBoot 引入
三、方法緩存
1. @Cached
使用@Cached方法可以為一個方法添加上緩存。JetCache通過Spring AOP生成代理,來支持緩存功能。注解可以加在接口方法上也可以加在類方法上,但需要保證是個Spring bean。
@Cached(name = "bxcCache:", cacheType = CacheType.BOTH, key = "#id", expire = 30, timeUnit = TimeUnit.MINUTES) public String getCache(String id) {System.out.println("哈哈哈哈");return "abc"; }@CacheUpdate(name = "bxcCache:", key = "#id", value = "#result") public String updateCache(String id) {return "update"; }@CacheInvalidate(name = "bxcCache:", key = "#id") public String deleteCache(String id){return "delete"; }上面代碼中可以看出,我們可以使用SpEL(Spring Expression Language)來設置key和Value。name屬性不是必須的,但是起個名字是個好習慣,展示統計數據的使用,會使用這個名字。如果同一個area兩個@CreateCache的name配置一樣,它們生成的Cache將指向同一個實例。這里面需要注意的是,java代碼的編輯級別必須是1.8。
其中CacheType
CacheType.REMOTE 遠程緩存,如:redis
CacheType.LOCAL本地緩存,如:linkedhashmap、caffeine
CacheType.BOTH 本地+遠程緩存,二級緩存
@CacheUpdate和@CacheInvalidate的name和area屬性必須和@Cached相同,name屬性還會用做cache的key前綴。
@Cached注解和@CreateCache的屬性非常類似,但是多幾個:
| area | “default” | 如果在配置中配置了多個緩存area,在這里指定使用哪個area |
| name | 未定義 | 指定緩存的唯一名稱,不是必須的,如果沒有指定,會使用類名+方法名。name會被用于遠程緩存的key前綴。另外在統計中,一個簡短有意義的名字會提高可讀性。 |
| key | 未定義 | 使用SpEL指定key,如果沒有指定會根據所有參數自動生成。 |
| expire | 未定義 | 超時時間。如果注解上沒有定義,會使用全局配置,如果此時全局配置也沒有定義,則為無窮大 |
| timeUnit | TimeUnit.SECONDS | 指定expire的單位 |
| cacheType | CacheType.REMOTE | 緩存的類型,包括CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定義為BOTH,會使用LOCAL和REMOTE組合成兩級緩存 |
| localLimit | 未定義 | 如果cacheType為LOCAL或BOTH,這個參數指定本地緩存的最大元素數量,以控制內存占用。如果注解上沒有定義,會使用全局配置,如果此時全局配置也沒有定義,則為100 |
| localExpire | 未定義 | 僅當cacheType為BOTH時適用,為內存中的Cache指定一個不一樣的超時時間,通常應該小于expire |
| serialPolicy | 未定義 | 指定遠程緩存的序列化方式。可選值為SerialPolicy.JAVA和SerialPolicy.KRYO。如果注解上沒有定義,會使用全局配置,如果此時全局配置也沒有定義,則為SerialPolicy.JAVA |
| keyConvertor | 未定義 | 指定KEY的轉換方式,用于將復雜的KEY類型轉換為緩存實現可以接受的類型,當前支持KeyConvertor.FASTJSON和KeyConvertor.NONE。NONE表示不轉換,FASTJSON可以將復雜對象KEY轉換成String。如果注解上沒有定義,會使用全局配置。 |
| enabled | true | 是否激活緩存。例如某個dao方法上加緩存注解,由于某些調用場景下不能有緩存,所以可以設置enabled為false,正常調用不會使用緩存,在需要的地方可使用CacheContext.enableCache在回調中激活緩存,緩存激活的標記在ThreadLocal上,該標記被設置后,所有enable=false的緩存都被激活 |
| cacheNullValue | false | 當方法返回值為null的時候是否要緩存 |
| condition | 未定義 | 使用SpEL指定條件,如果表達式返回true的時候才去緩存中查詢 |
| postCondition | 未定義 | 使用SpEL指定條件,如果表達式返回true的時候才更新緩存,該評估在方法執行后進行,因此可以訪問到#result |
2. @CacheRefresh 自動刷新
@CacheRefresh 相當于開始一個定時任務,定時刷新值到緩存中。
@Cached(name = "bxcCache:", cacheType = CacheType.BOTH, key = "#id", expire = 30, timeUnit = TimeUnit.MINUTES) @CacheRefresh(refresh = 2, stopRefreshAfterLastAccess = 10, timeUnit = TimeUnit.SECONDS) public String getCache(String id) {System.out.println("哈哈哈哈");return "abc"; }refresh 刷新時間周期
stopRefreshAfterLastAccess 停止刷新周期
timeUnit 時間單位
運行效果:
@CacheRefresh注解說明:
| refresh | 未定義 | 刷新間隔 |
| timeUnit | TimeUnit.SECONDS | 時間單位 |
| stopRefreshAfterLastAccess | 未定義 | 指定該key多長時間沒有訪問就停止刷新,如果不指定會一直刷新 |
| refreshLockTimeout | 60秒 | 類型為BOTH/REMOTE的緩存刷新時,同時只會有一臺服務器在刷新,這臺服務器會在遠程緩存放置一個分布式鎖,此配置指定該鎖的超時時間 |
3. @CachePenetrationProtect 同步加載數據
當緩存訪問未命中的情況下,對并發進行的加載行為進行保護。 當前版本實現的是單JVM內的保護,即同一個JVM中同一個key只有一個線程去加載,其它線程等待結果。
@Cached(name = "bxcCache:", cacheType = CacheType.BOTH, key = "#id", expire = 30, timeUnit = TimeUnit.MINUTES) @CachePenetrationProtect public String getCache(String id) {System.out.println("哈哈哈哈");return "abc"; }參數解析:
四、緩存API
使用@CreateCache注解去創建一個Cache實例
@CreateCache(expire = 100, cacheType = CacheType.BOTH, localLimit = 50) private Cache<Long, UserDO> userCache;expire 超時時間
cacheType 緩存類型
localLimit 限制緩存數量
五、異步API
從JetCache2.2版本開始,所有的大寫API返回的CacheResult都支持異步。當底層的緩存實現支持異步的時候,大寫API返回的結果都是異步的。當前支持異步的實現只有jetcache的redis-luttece實現,其他的緩存實現(內存中的、Tair、Jedis等),所有的異步接口都會同步堵塞,這樣API仍然是兼容的。
CacheGetResult<UserDO> r = cache.GET(userId);這一行代碼執行完以后,緩存操作可能還沒有完成,如果此時調用r.isSuccess()或者r.getValue()或者r.getMessage()將會堵塞直到緩存操作完成。如果不想被堵塞,并且需要在緩存操作完成以后執行后續操作,可以這樣做:
CompletionStage<ResultData> future = r.future(); future.thenRun(() -> {if(r.isSuccess()){System.out.println(r.getValue());} });以上代碼將會在緩存操作異步完成后,在完成異步操作的線程中調用thenRun中指定的回調。CompletionStage是Java8新增的功能,如果對此不太熟悉可以先查閱相關的文檔。需要注意的是,既然已經選擇了異步的開發方式,在回調中不能調用堵塞方法,以免堵塞其他的線程(回調方法很可能是在event loop線程中執行的)。
部分小寫的api不需要任何修改,就可以直接享受到異步開發的好處。比如put和removeAll方法,由于它們沒有返回值,所以此時就直接優化成異步調用,能夠減少RT;而get方法由于需要取返回值,所以仍然會堵塞。
六、分布式鎖
boolean hasRun = cache.tryLockAndRun("liuxw3", 100, TimeUnit.SECONDS, () -> {System.out.println("我獲取到鎖了"); });總結
以上是生活随笔為你收集整理的阿里开源 JetCache 缓存框架介绍使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员的跳槽人生(跳槽攻略)
- 下一篇: 找不到引道分区_惠普笔记本单固态分区教程