Spring – 緩存註解

Spring緩存抽象概述

Spring框架自身並無實現緩存解決方案,可是從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口,提供對緩存功能的聲明,可以與多種流行的緩存實現集成。spring

Cache接口爲緩存的組件規範定義,包含緩存的各類操做集合;數組

Cache接口下Spring提供了各類xxxCache的實現:如RedisCache,EhCacheCache , ConcurrentMapCache等;緩存

CacheManager接口爲緩存管理器規範,簡單來講就是用於存放cache,Spring默認也提供了一些列管理器的實現。app

Spring緩存抽象提供了5個註解用來聲明緩存規則:框架

@Cacheable:可以根據方法的請求參數對其結果進行緩存,多用於查詢less

@CachePut: 執行方法,並緩存結果異步

@CacheEvict:清空緩存ide

@Caching:可以同時應用多個緩存註解功能測試

@CacheConfig: 用於抽取緩存的公共配置(類級別)spa

以上5個註解除了@CacheConfig註解是類級別的註解,其他4個註解在類和方法上都可以使用,做用在類上表示對該類下全部方法生效,做用的方法上只對該方法生效,且只能用於public修飾的符方法,protected或者private修飾的方法不適用。

@Cacheable註解

@Cacheable註解的做用是Spring在調用該方法以前,首先在緩存中查找方法的返回值,默認的key是根據參數值生成,若是存在,直接返回緩存中的值,不然執行該方法,並將返回值保存到緩存中

@Cacheable運行流程:

  1.方法運行以前,先去查詢Cache(緩存組件),按照cacheNames指定的名字獲取;

           (CacheManager先獲取相應的緩存),第一次獲取緩存若是沒有Cache組件會自動建立。

  2.去Cache中查找緩存的內容,使用一個key,默認就是方法的參數值;

           key是按照某種策略生成的;默認是使用keyGenerator生成的,               

     Spring默認加載的是SimpleCacheManage,SimpleKeyGenerator生成key的默認策略是:

                       若是沒有參數;key=new SimpleKey()

                       若是有一個參數:key=參數的值

                       若是有多個參數:key=new SimpleKey(params)

  3.沒有查到緩存就調用目標方法;

  4.將目標方法返回的結果,放進緩存中

@Cacheable屬性說明:

  1.acheNames/value:該屬性值必須提供,指定緩存組件的名字,將方法的返回結果放在哪一個緩存中,是數組的方式,能夠指定多個緩存;

      如:cacheNames = "product"或者cacheNames = {"product1","product2"}

  2.key:緩存數據使用的key,不指定key則默認是使用方法參數的值該屬性值支持SpEL表達式

       3.cacheManager:指定緩存管理器;或者cacheResolver指定獲取解析器

       4.condition:指定符合條件的狀況下才緩存

  5.unless:否認緩存;當unless指定的條件爲true,方法的返回值就不會被緩存;能夠獲取到結果進行判斷

                  unless = "#result == null"

                   unless = "#a0==2":若是第一個參數的值是2,結果不緩存;

  6.sync:是否使用異步模式

使用示例:

 1 @Cacheable(cacheNames = "product")// 默認key爲參數,多個參數SimpleKey [arg1,arg2]
 2 //@Cacheable(cacheNames = "product",key = "#root.methodName+'['+#id+']'")
 3 //@Cacheable(cacheNames = "product",keyGenerator = "myKeyGenerator")
 4 //@Cacheable(cacheNames = "product",key = "#root.methodName+'['+#id+']'",condition="#a0>10",unless = "#a0==11") //帶條件的緩存知足condition=true緩存,知足unless=true則不緩存 
 5 public Product getProductById(Long id){
 6    Product product =productMapper.getProductById(id);
 7    System.out.println(product);
 8    return product;
 9 }
10 //指定key屬性值 11 @Cacheable(cacheNames ="product", key="#id") //」#+參數名」的形式,直接使用參數名 12 //或者 13 //@Cacheable(cacheNames ="product", key="#a0") //」#a+參數位置」的形式 14 public Product getProductById(long id) { 15 xxxx 16 } 17 @Cacheable(cacheNames ="product", key="# productcondition.productId") 18 //或者 19 //@Cacheable(cacheNames ="product", key="#a0.productId") 20 public Product getProduct (Product productcondition) { 21 xxxx 22 }

自定義Key生成器

除了經過SPEL表達式以外,還能夠經過自定義key生成器的方式,Spring緩存模塊提供了org.springframework.cache.interceptor.KeyGenerator接口用於緩存key的生成聲明,所以咱們能夠自定義一個MyKeyGenerator類並實現了KeyGenerator接口 ,使用以下:

 1 @Configuration
 2 public class MyCacheConfig {
 3 
 4     @Bean("myKeyGenerator")
 5     public KeyGenerator keyGenerator(){
 6         return new KeyGenerator(){
 7 
 8             @Override
 9             public Object generate(Object target, Method method, Object... params) {
10                 return method.getName()+"["+ Arrays.asList(params).toString()+"]";
11             }
12         };
13     }
14 }

該方法測試用,關於緩存key的生成方式,網上有不少種策略。

使用時只須要修改註解的key屬性便可:

1 @Cacheable(cacheNames = "product",keyGenerator = "myKeyGenerator")

  @CachePut

@CachePut註解的做用簡單的說一句話:既調用方法,又緩存數據。@cachePut和@Cacheable兩個註解均可以用於填充緩存,但使用上略有點差別,@Cacheable註解的執行流程是先在按key在緩存中查找,存在則返回,不存在則執行目標方法,並緩存目標方法的結果。而@CachePut並不會檢查緩存,老是先執行目標方法,並將目標方法的結果保存到緩存中。實際中好比執行到更新操做時,則但願將最新的數據更新到緩存,若是該方法返回異常,將再也不執行保存緩存的邏輯。

@CachePut屬性說明

@CachePut註解屬性與@CachePut相似,並無增長其餘屬性

使用示例:

 1 @CachePut(value="product",key = "#result.productId",condition = "#result!=null")
 2 public  Product updateProduct(Product product){
 3     int count = productMapper.updateProduct(product);
 4     System.out.println("影響行數:"+count);
 5     if(count>0){
 6         return product;
 7     }else{
 8         return null;
 9     }
10 }

@CacheEvict註解

該註解的做用根據指定的key或者是allEntries屬性值移除緩存中特性的鍵值對。

@CacheEvict屬性說明

與@Cacheable相比@CacheEvict註解提供了另外兩個屬性:

  1. allEntries:表示是否清空全部緩存內容,默認false,若是該值爲true則清空指定cacheNames緩存塊下全部內容,若是指定了allEntries爲true,那麼再zhidingkey值將沒有意義

  2. beforeInvocation:是否在執行方法前請空緩存,默認值爲false,若是該值爲true則在調用目標方法前執行清空緩存,爲false的狀況下,若是目標方法拋出異常,則再也不執行清空緩存邏輯

示例:

1 //@CacheEvict(value="product",key="#id")
2 //@CacheEvict(value="product",allEntries = true) //清楚全部緩存
3 @CacheEvict(value="product",allEntries = true,beforeInvocation = true) //清楚全部緩存
4 public boolean deleteProductById(Long id) {
5     productMapper.deleteProductById(id);
6     return true;
7 }

@Caching註解

該註解是一個分組註解,做用是能夠同時應用多個其餘註解,該註解提供了3個屬性cacheable,put,evict分別用於組合@Cacheable、@CachePut、@CacheEvict三個註解

使用示例:

 1 @Caching(
 2         cacheable = {@Cacheable(value="product",key="#productName")},
 3         put = {
 4                 @CachePut(value="product",key="#result.productId"),
 5                 @CachePut(value="product",key="#result.productName")
 6         }
 7 )
 8 public  Product getProductByName(String productName){
 9 
10     Product product =productMapper.getProductByName(productName);
11 
12      return product;
13 }

當@Cacheing同時含有CachePut註解和Cacheable註解時,仍然會先執行目標方法。(並非按@Cacheable的執行過程,先檢查緩存,存在則返回)

@CacheConfig

是一個類級別的註解,容許共享緩存的名稱、KeyGenerator、CacheManager 和CacheResolver

示例:

1 @Service
2 @CacheConfig(cacheNames = "product")
3 public class ProductService {
4 }

在類上使用該註解,指定cacheNames屬性值,則類中方法上的註解將默認繼承了該屬性值,若是方法上註解使用和了@CacheConfig向同的屬性,則以方法上的爲準。

 1 @Service
 2 @CacheConfig(cacheNames = "product")
 3 public class ProductService {
 4     @Autowired
 5     private ProductMapper productMapper;
 6 
 7     @Cacheable(cacheNames = "product1",key = "#root.methodName+'['+#id+']'")
 8     public Product getProductById(Long id){
 9        Product product =productMapper.getProductById(id);
10        System.out.println(product);
11        return product;
12     }
13 }

上面@Cacheable和@CacheConfig都指定了屬性值cacaeNames,實際以方法上註解指定的爲準。

 

Spring緩存抽象的關鍵原理就是使用spring AOP,經過切面實現了在方法調用前、調用後獲取方法的入參和返回值,進而實現了緩存的邏輯。有一點須要注意的是Spring Aop是經過動態代理機制來實現對目標方法的調用,因此若是該註解方法是在類內部調用而不是在類外部調用,將會致使動態代理時效,從而致使該註解功能時效。

相關文章
相關標籤/搜索