javascript
SpringBoot基础系列-SpringCache使用
原創文章,轉載請標注出處:《SpringBoot基礎系列-SpringCache使用》
一、概述
SpringCache本身是一個緩存體系的抽象實現,并沒有具體的緩存能力,要使用SpringCache還需要配合具體的緩存實現來完成。
雖然如此,但是SpringCache是所有Spring支持的緩存結構的基礎,而且所有的緩存的使用最后都要歸結于SpringCache,那么一來,要想使用SpringCache,還是要仔細研究一下的。
二、緩存注解
SpringCache緩存功能的實現是依靠下面的這幾個注解完成的。
- @EnableCaching:開啟緩存功能
- @Cacheable:定義緩存,用于觸發緩存
- @CachePut:定義更新緩存,觸發緩存更新
- @CacheEvict:定義清除緩存,觸發緩存清除
- @Caching:組合定義多種緩存功能
@CacheConfig:定義公共設置,位于class之上
2.1 @EnableCaching
該注解主要用于開啟基于注解的緩存功能,使用方式為:
注意:在SpringBoot中使用SpringCache可以由自動配置功能來完成CacheManager的注冊,SpringBoot會自動發現項目中擁有的緩存系統,而注冊對應的緩存管理器,當然我們也可以手動指定。
使用該注解和如下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 {// 用于設置使用哪種代理方式,默認為基于接口的JDK動態代理(false),// 設置為true,則使用基于繼承的CGLIB動態代理boolean proxyTargetClass() default false;// 用于設置切面織入方式(設置面向切面編程的實現方式),// 默認為使用動態代理的方式織入,當然也可以設置為ASPECTJ的方式來實現AOPAdviceMode mode() default AdviceMode.PROXY;// 用于設置在一個切點存在多個通知的時候各個通知的執行順序,默認為最低優先級,// 其中數字卻大優先級越低,這里默認為最低優先級,int LOWEST_PRECEDENCE =// Integer.MAX_VALUE;,卻是整數的最大值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來實現的。
2.2 @Cacheable
該注解用于標注于方法之上用于標識該方法的返回結果需要被緩存起來,標注于類之上標識該類中所有方法均需要將結果緩存起來。
該注解標注的方法每次被調用前都會觸發緩存校驗,校驗指定參數的緩存是否已存在(已發生過相同參數的調用),若存在,直接返回緩存結果,否則執行方法內容,最后將方法執行結果保存到緩存中。
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));}//... }上面的實例中兩個@Cacheable配置效果其實是一樣的,其中value指定的緩存的名稱,它和另一個方法cacheName效果一樣,一般來說這個緩存名稱必須要有,因為這個是區別于其他方法的緩存的唯一方法。
這里我們介紹一下緩存的簡單結構,在緩存中,每個這樣的緩存名稱的名下都會存在著多個緩存條目,這些緩存條目對應在使用不同的參數調用當前方法時生成的緩存,所有一個緩存名稱并不是一個緩存,而是一系列緩存。
另一個key用于指定當前方法的緩存保存時的鍵的組合方式,默認的情況下使用所有的參數組合而成,這樣可以有效區分不同參數的緩存。當然我們也可以手動指定,指定的方法是使用SPEL表達式。
這里我么來簡單看看其源碼,了解下其他幾個方法的作用:
@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手動指定緩存鍵的組合方式,默認情況使用所有的參數來組合成鍵,除非自定義了keyGenerator。// 使用SPEL表達式可以根據上下文環境來獲取到指定的數據:// #root.method:用于獲取當前方法的Method實例// #root.target:用于獲取當前方法的target實例// #root.caches:用于獲取當前方法關聯的緩存// #root.methodName:用于獲取當前方法的名稱// #root.targetClass:用于獲取目標類類型// #root.args[1]:獲取當前方法的第二個參數,等同于:#p1和#a1和#argumentNameString key() default "";// 自定義鍵生成器,定義了該方法之后,上面的key方法自動失效,這個鍵生成器是:// org.springframework.cache.interceptor.KeyGenerator,這是一個函數式接口,// 只有一個generate方法,我們可以通過自定義的邏輯來實現自定義的key生成策略。String keyGenerator() default "";// 用于設置自定義的cacheManager(緩存管理器),可以自動生成一個cacheResolver// (緩存解析器),這一下面的cacheResolver()方法設置互斥String cacheManager() default "";// 用于設置一個自定義的緩存解析器String cacheResolver() default "";// 用于設置執行緩存的條件,如果條件不滿足,方法返回的結果就不會被緩存,默認無條件全部緩存。// 同樣使用SPEL來定義條件,可以使用的獲取方式同key方法。String condition() default "";// 這個用于禁止緩存功能,如果設置的條件滿足,就不執行緩存結果,與上面的condition不同之處在于,// 該方法執行在當前方法調用結束,結果出來之后,因此,它除了可以使用上面condition所能使用的SPEL// 表達式之外,還可以使用#result來獲取方法的執行結果,亦即可以根據結果的不同來決定是否緩存。String unless() default "";// 設置是否對多個針對同一key執行緩存加載的操作的線程進行同步,默認不同步。這個功能需要明確確定所// 使用的緩存工具支持該功能,否則不要濫用。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
該注解用于更新緩存,無論結果是否已經緩存,都會在方法執行結束插入緩存,相當于更新緩存。一般用于更新方法之上。
@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設置為id也與上面的key設置對應。
如此設置之后,每次執行update方法時都會直接執行方法內容,然后將返回的結果保存到緩存中,如果存在相同的key,直接替換緩存內容執行緩存更新。
下面來看看源碼:
@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 ""; }只有一點要注意:這里的設置一定要和執行緩存保存的方法的@Cacheable的設置一致,否則無法準確更新。
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 "";// 這個設置用于指定當前緩存名稱名下的所有緩存是否全部刪除,默認false。boolean allEntries() default false;// 這個用于指定刪除緩存的操作是否在方法調用之前完成,默認為false,表示先調用方法,在執行緩存刪除。boolean beforeInvocation() default false; }2.5 @Caching
這個注解用于組個多個緩存操作,包括針對不用緩存名稱的相同操作等,源碼:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Caching {// 用于指定多個緩存設置操作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
該注解標注于類之上,用于進行一些公共的緩存相關配置。源碼為:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CacheConfig {// 設置統一的緩存名,適用于整個類中的方法全部是針對同一緩存名操作的情況String[] cacheNames() default {};// 設置統一個鍵生成器,免去了每個緩存設置中單獨設置String keyGenerator() default "";// 設置統一個自定義緩存管理器String cacheManager() default "";// 設置統一個自定義緩存解析器String cacheResolver() default ""; }轉載于:https://www.cnblogs.com/V1haoge/p/10351734.html
總結
以上是生活随笔為你收集整理的SpringBoot基础系列-SpringCache使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫抓包工具
- 下一篇: python的_thread模块来实现多