javascript
SpringBoot基础系列-SpringCache使用
原創(chuàng)文章,轉(zhuǎn)載請標(biāo)注出處:《SpringBoot基礎(chǔ)系列-SpringCache使用》
一、概述
SpringCache本身是一個緩存體系的抽象實(shí)現(xiàn),并沒有具體的緩存能力,要使用SpringCache還需要配合具體的緩存實(shí)現(xiàn)來完成。
雖然如此,但是SpringCache是所有Spring支持的緩存結(jié)構(gòu)的基礎(chǔ),而且所有的緩存的使用最后都要?dú)w結(jié)于SpringCache,那么一來,要想使用SpringCache,還是要仔細(xì)研究一下的。
二、緩存注解
SpringCache緩存功能的實(shí)現(xiàn)是依靠下面的這幾個注解完成的。
- @EnableCaching:開啟緩存功能
- @Cacheable:定義緩存,用于觸發(fā)緩存
- @CachePut:定義更新緩存,觸發(fā)緩存更新
- @CacheEvict:定義清除緩存,觸發(fā)緩存清除
- @Caching:組合定義多種緩存功能
@CacheConfig:定義公共設(shè)置,位于class之上
2.1 @EnableCaching
該注解主要用于開啟基于注解的緩存功能,使用方式為:
注意:在SpringBoot中使用SpringCache可以由自動配置功能來完成CacheManager的注冊,SpringBoot會自動發(fā)現(xiàn)項(xiàng)目中擁有的緩存系統(tǒng),而注冊對應(yīng)的緩存管理器,當(dāng)然我們也可以手動指定。
使用該注解和如下XML配置具有一樣的效果:
<beans><cache:annotation-driven/><bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager><property name="caches"><set><bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean><property name="name" value="default"/></bean></set></property></bean> </beans>下面來看看@EnableCaching的源碼:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(CachingConfigurationSelector.class) public @interface EnableCaching {// 用于設(shè)置使用哪種代理方式,默認(rèn)為基于接口的JDK動態(tài)代理(false),// 設(shè)置為true,則使用基于繼承的CGLIB動態(tài)代理boolean proxyTargetClass() default false;// 用于設(shè)置切面織入方式(設(shè)置面向切面編程的實(shí)現(xiàn)方式),// 默認(rèn)為使用動態(tài)代理的方式織入,當(dāng)然也可以設(shè)置為ASPECTJ的方式來實(shí)現(xiàn)AOPAdviceMode mode() default AdviceMode.PROXY;// 用于設(shè)置在一個切點(diǎn)存在多個通知的時候各個通知的執(zhí)行順序,默認(rèn)為最低優(yōu)先級,// 其中數(shù)字卻大優(yōu)先級越低,這里默認(rèn)為最低優(yōu)先級,int LOWEST_PRECEDENCE =// Integer.MAX_VALUE;,卻是整數(shù)的最大值int order() default Ordered.LOWEST_PRECEDENCE; } public enum AdviceMode {PROXY,ASPECTJ } public interface Ordered {int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;int LOWEST_PRECEDENCE = Integer.MAX_VALUE;int getOrder(); }由上面的源碼可以看出,緩存功能是依靠AOP來實(shí)現(xiàn)的。
2.2 @Cacheable
該注解用于標(biāo)注于方法之上用于標(biāo)識該方法的返回結(jié)果需要被緩存起來,標(biāo)注于類之上標(biāo)識該類中所有方法均需要將結(jié)果緩存起來。
該注解標(biāo)注的方法每次被調(diào)用前都會觸發(fā)緩存校驗(yàn),校驗(yàn)指定參數(shù)的緩存是否已存在(已發(fā)生過相同參數(shù)的調(diào)用),若存在,直接返回緩存結(jié)果,否則執(zhí)行方法內(nèi)容,最后將方法執(zhí)行結(jié)果保存到緩存中。
2.2.1 使用
@Service @Log4j2 public class AnimalService {@Autowiredprivate AnimalRepository animalRepository;//... // @Cacheable("animalById")@Cacheable(value = "animalById", key = "#id")public ResponseEntity<Animal> getAnimalById(final int id){return ResponseEntity.ok(animalRepository.selectById(id));}//... }上面的實(shí)例中兩個@Cacheable配置效果其實(shí)是一樣的,其中value指定的緩存的名稱,它和另一個方法cacheName效果一樣,一般來說這個緩存名稱必須要有,因?yàn)檫@個是區(qū)別于其他方法的緩存的唯一方法。
這里我們介紹一下緩存的簡單結(jié)構(gòu),在緩存中,每個這樣的緩存名稱的名下都會存在著多個緩存條目,這些緩存條目對應(yīng)在使用不同的參數(shù)調(diào)用當(dāng)前方法時生成的緩存,所有一個緩存名稱并不是一個緩存,而是一系列緩存。
另一個key用于指定當(dāng)前方法的緩存保存時的鍵的組合方式,默認(rèn)的情況下使用所有的參數(shù)組合而成,這樣可以有效區(qū)分不同參數(shù)的緩存。當(dāng)然我們也可以手動指定,指定的方法是使用SPEL表達(dá)式。
這里我么來簡單看看其源碼,了解下其他幾個方法的作用:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Cacheable {// 用于指定緩存名稱,與cacheNames()方法效果一致@AliasFor("cacheNames")String[] value() default {};// 用于指定緩存名稱,與value()方法效果一致@AliasFor("value")String[] cacheNames() default {};// 用于使用SPEL手動指定緩存鍵的組合方式,默認(rèn)情況使用所有的參數(shù)來組合成鍵,除非自定義了keyGenerator。// 使用SPEL表達(dá)式可以根據(jù)上下文環(huán)境來獲取到指定的數(shù)據(jù):// #root.method:用于獲取當(dāng)前方法的Method實(shí)例// #root.target:用于獲取當(dāng)前方法的target實(shí)例// #root.caches:用于獲取當(dāng)前方法關(guān)聯(lián)的緩存// #root.methodName:用于獲取當(dāng)前方法的名稱// #root.targetClass:用于獲取目標(biāo)類類型// #root.args[1]:獲取當(dāng)前方法的第二個參數(shù),等同于:#p1和#a1和#argumentNameString key() default "";// 自定義鍵生成器,定義了該方法之后,上面的key方法自動失效,這個鍵生成器是:// org.springframework.cache.interceptor.KeyGenerator,這是一個函數(shù)式接口,// 只有一個generate方法,我們可以通過自定義的邏輯來實(shí)現(xiàn)自定義的key生成策略。String keyGenerator() default "";// 用于設(shè)置自定義的cacheManager(緩存管理器),可以自動生成一個cacheResolver// (緩存解析器),這一下面的cacheResolver()方法設(shè)置互斥String cacheManager() default "";// 用于設(shè)置一個自定義的緩存解析器String cacheResolver() default "";// 用于設(shè)置執(zhí)行緩存的條件,如果條件不滿足,方法返回的結(jié)果就不會被緩存,默認(rèn)無條件全部緩存。// 同樣使用SPEL來定義條件,可以使用的獲取方式同key方法。String condition() default "";// 這個用于禁止緩存功能,如果設(shè)置的條件滿足,就不執(zhí)行緩存結(jié)果,與上面的condition不同之處在于,// 該方法執(zhí)行在當(dāng)前方法調(diào)用結(jié)束,結(jié)果出來之后,因此,它除了可以使用上面condition所能使用的SPEL// 表達(dá)式之外,還可以使用#result來獲取方法的執(zhí)行結(jié)果,亦即可以根據(jù)結(jié)果的不同來決定是否緩存。String unless() default "";// 設(shè)置是否對多個針對同一key執(zhí)行緩存加載的操作的線程進(jìn)行同步,默認(rèn)不同步。這個功能需要明確確定所// 使用的緩存工具支持該功能,否則不要濫用。boolean sync() default false; }如何自定義一個KeyGenerator呢?
public class AnimalKeyGenerator implements KeyGenerator {@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder sb = new StringBuilder("animal-");sb.append(target.getClass().getSimpleName()).append("-").append(method.getName()).append("-");for (Object o : params) {String s = o.toString();sb.append(s).append("-");}return sb.deleteCharAt(sb.lastIndexOf("-")).toString();} }2.3 @CachePut
該注解用于更新緩存,無論結(jié)果是否已經(jīng)緩存,都會在方法執(zhí)行結(jié)束插入緩存,相當(dāng)于更新緩存。一般用于更新方法之上。
@Service @Log4j2 public class AnimalService {@Autowiredprivate AnimalRepository animalRepository;//...@CachePut(value = "animalById", key = "#animal.id")public ResponseEntity<Animal> updateAnimal(final Animal animal){Wrapper<Animal> animalWrapper = new UpdateWrapper<>();((UpdateWrapper<Animal>) animalWrapper).eq("id",animal.getId());animalRepository.update(animal, animalWrapper);return ResponseEntity.ok(this.getAnimalById(animal.getId()));}//... }這里指定更新緩存,value同樣還是緩存名稱,這里更新的是上面查詢操作的同一緩存,而且key設(shè)置為id也與上面的key設(shè)置對應(yīng)。
如此設(shè)置之后,每次執(zhí)行update方法時都會直接執(zhí)行方法內(nèi)容,然后將返回的結(jié)果保存到緩存中,如果存在相同的key,直接替換緩存內(nèi)容執(zhí)行緩存更新。
下面來看看源碼:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface CachePut {// 同上@AliasFor("cacheNames")String[] value() default {};// 同上@AliasFor("value")String[] cacheNames() default {};// 同上String key() default "";// 同上String keyGenerator() default "";// 同上String cacheManager() default "";// 同上String cacheResolver() default "";// 同上String condition() default "";// 同上String unless() default ""; }只有一點(diǎn)要注意:這里的設(shè)置一定要和執(zhí)行緩存保存的方法的@Cacheable的設(shè)置一致,否則無法準(zhǔn)確更新。
2.4 @CacheEvict
該注解主要用于刪除緩存操作。
@Service @Log4j2 public class AnimalService {@Autowiredprivate AnimalRepository animalRepository;//...@CacheEvict(value = "animalById", key = "#id")public ResponseEntity<Integer> deleteAnimalById(final int id){return ResponseEntity.ok(animalRepository.deleteById(id));}//... }簡單明了,看看源碼:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface CacheEvict {// 同上@AliasFor("cacheNames")String[] value() default {};// 同上@AliasFor("value")String[] cacheNames() default {};// 同上String key() default "";// 同上String keyGenerator() default "";// 同上String cacheManager() default "";// 同上String cacheResolver() default "";// 同上String condition() default "";// 這個設(shè)置用于指定當(dāng)前緩存名稱名下的所有緩存是否全部刪除,默認(rèn)false。boolean allEntries() default false;// 這個用于指定刪除緩存的操作是否在方法調(diào)用之前完成,默認(rèn)為false,表示先調(diào)用方法,在執(zhí)行緩存刪除。boolean beforeInvocation() default false; }2.5 @Caching
這個注解用于組個多個緩存操作,包括針對不用緩存名稱的相同操作等,源碼:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Caching {// 用于指定多個緩存設(shè)置操作Cacheable[] cacheable() default {};// 用于指定多個緩存更新操作CachePut[] put() default {};// 用于指定多個緩存失效操作CacheEvict[] evict() default {}; }簡單用法:
@Service @Log4j2 public class AnimalService {@Autowiredprivate AnimalRepository animalRepository;//...@Caching(evict = {@CacheEvict(value = "animalById", key = "#id"),@CacheEvict(value = "animals", allEntries = true, beforeInvocation = true)})public ResponseEntity<Integer> deleteAnimalById(final int id){return ResponseEntity.ok(animalRepository.deleteById(id));}@Cacheable("animals")public ResponseEntity<Page<Animal>> getAnimalPage(final Animal animal, final int pageId, final int pageSize){Page<Animal> page = new Page<>();page.setCurrent(pageId);page.setSize(pageSize);return ResponseEntity.ok((Page<Animal>) animalRepository.selectPage(page,packWrapper(animal, WrapperType.QUERY)));}//... }2.6 @CacheConfig
該注解標(biāo)注于類之上,用于進(jìn)行一些公共的緩存相關(guān)配置。源碼為:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CacheConfig {// 設(shè)置統(tǒng)一的緩存名,適用于整個類中的方法全部是針對同一緩存名操作的情況String[] cacheNames() default {};// 設(shè)置統(tǒng)一個鍵生成器,免去了每個緩存設(shè)置中單獨(dú)設(shè)置String keyGenerator() default "";// 設(shè)置統(tǒng)一個自定義緩存管理器String cacheManager() default "";// 設(shè)置統(tǒng)一個自定義緩存解析器String cacheResolver() default ""; }轉(zhuǎn)載于:https://www.cnblogs.com/V1haoge/p/10351734.html
總結(jié)
以上是生活随笔為你收集整理的SpringBoot基础系列-SpringCache使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫抓包工具
- 下一篇: python的_thread模块来实现多