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