1. 程式人生 > 實用技巧 >Spring快取註解

Spring快取註解

Spring快取註解簡介

Spring為我們提供了幾個註解來支援Spring Cache。其核心主要是@Cacheable和@CacheEvict。使用@Cacheable標記的方法在執行後Spring Cache將快取其返回結果,而使用@CacheEvict標記的方法會在方法執行前或者執行後移除Spring Cache中的某些元素。

@Cacheable

@Cacheable可以標記在一個方法上,也可以標記在一個類上。當標記在一個方法上時表示該方法是支援快取的,當標記在一個類上時則表示該類所有的方法都是支援快取的。對於一個支援快取的方法,Spring會在其被呼叫後將其返回值快取起來,以保證下次利用同樣的引數來執行該方法時可以直接從快取中獲取結果,而不需要再次執行該方法。Spring在快取方法的返回值時是以鍵值對進行快取的,值就是方法的返回結果,至於鍵的話,Spring又支援兩種策略,預設策略和自定義策略,這個稍後會進行說明。需要注意的是當一個支援快取的方法在物件內部被呼叫時是不會觸發快取功能的。@Cacheable可以指定三個屬性,value、key和condition。

value屬性指定Cache名稱

value屬性是必須指定的,其表示當前方法的返回值是會被快取在哪個Cache上的,對應Cache的名稱。其可以是一個Cache也可以是多個Cache,當需要指定多個Cache時其是一個數組。

   @Cacheable("cache1")//Cache是發生在cache1上的

   public User find(Integer id) {

      return null;

   }

 

   @Cacheable({"cache1", "cache2"})//Cache是發生在cache1和cache2上的

   public User find(Integer id) {

      return null;

   }

使用key屬性自定義key

key屬性是用來指定Spring快取方法的返回結果時對應的key的。該屬性支援SpringEL表示式。當我們沒有指定該屬性時,Spring將使用預設策略生成key。我們這裡先來看看自定義策略,至於預設策略會在後文單獨介紹。

自定義策略是指我們可以通過Spring的EL表示式來指定我們的key。這裡的EL表示式可以使用方法引數及它們對應的屬性。使用方法引數時我們可以直接使用“#引數名”或者“#p引數index”。下面是幾個使用引數作為key的示例。

   @Cacheable(value="users", key="#id")

   public User find(Integer id) {

      return null;

   }

 

   @Cacheable(value="users", key="#p0")

   public User find(Integer id) {

      return null;

   }

 

   @Cacheable(value="users", key="#user.id")

   public User find(User user) {

      return null;

   }

 

   @Cacheable(value="users", key="#p0.id")

   public User find(User user) {

      return null;

   }

除了上述使用方法引數作為key之外,Spring還為我們提供了一個root物件可以用來生成key。通過該root物件我們可以獲取到以下資訊。
| 屬性名稱 |描述 |示例 |
| ---- | ---- |
|methodName | 當前方法名 |#root.methodName |
| method | 當前方法 |#root.method.name |
| target| 當前被呼叫的物件 |#root.target |
| targetClass | 當前被呼叫的物件的class |#root.targetClass |
|args | 當前方法引數組成的陣列 | #root.args[0] |
| caches | 當前被呼叫的方法使用的Cache | #root.caches[0].name |

當我們要使用root物件的屬性作為key時我們也可以將“#root”省略,因為Spring預設使用的就是root物件的屬性。如:

   @Cacheable(value={"users", "xxx"}, key="caches[1].name")

   public User find(User user) {

      return null;

   }

condition屬性指定發生的條件

有的時候我們可能並不希望快取一個方法所有的返回結果。通過condition屬性可以實現這一功能。condition屬性預設為空,表示將快取所有的呼叫情形。其值是通過SpringEL表示式來指定的,當為true時表示進行快取處理;當為false時表示不進行快取處理,即每次呼叫該方法時該方法都會執行一次。如下示例表示只有當user的id為偶數時才會進行快取。

   @Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")

   public User find(User user) {

      System.out.println("find user by user " + user);

      return user;

   }

@CachePut

在支援Spring Cache的環境下,對於使用@Cacheable標註的方法,Spring在每次執行前都會檢查Cache中是否存在相同key的快取元素,如果存在就不再執行該方法,而是直接從快取中獲取結果進行返回,否則才會執行並將返回結果存入指定的快取中。@CachePut也可以宣告一個方法支援快取功能。與@Cacheable不同的是使用@CachePut標註的方法在執行前不會去檢查快取中是否存在之前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的快取中。

@CachePut也可以標註在類上和方法上。使用@CachePut時我們可以指定的屬性跟@Cacheable是一樣的。

   @CachePut("users")//每次都會執行方法,並將結果存入指定的快取中

   public User find(Integer id) {

      returnnull;

   }

@CacheEvict

@CacheEvict是用來標註在需要清除快取元素的方法或類上的。當標記在一個類上時表示其中所有的方法的執行都會觸發快取的清除操作。@CacheEvict可以指定的屬性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的語義與@Cacheable對應的屬性類似。即value表示清除操作是發生在哪些Cache上的(對應Cache的名稱);key表示需要清除的是哪個key,如未指定則會使用預設策略生成的key;condition表示清除操作發生的條件。下面我們來介紹一下新出現的兩個屬性allEntries和beforeInvocation。

allEntries屬性

allEntries是boolean型別,表示是否需要清除快取中的所有元素。預設為false,表示不需要。當指定了allEntries為true時,Spring Cache將忽略指定的key。有的時候我們需要Cache一下清除所有的元素,這比一個一個清除元素更有效率。

   @CacheEvict(value="users", allEntries=true)

   public void delete(Integer id) {

      System.out.println("delete user by id: " + id);

   }

beforeInvocation屬性

清除操作預設是在對應方法成功執行之後觸發的,即方法如果因為丟擲異常而未能成功返回時也不會觸發清除操作。使用beforeInvocation可以改變觸發清除操作的時間,當我們指定該屬性值為true時,Spring會在呼叫該方法之前清除快取中的指定元素。

   @CacheEvict(value="users", beforeInvocation=true)

   public void delete(Integer id) {

      System.out.println("delete user by id: " + id);

   }

其實除了使用@CacheEvict清除快取元素外,當我們使用Ehcache作為實現時,我們也可以配置Ehcache自身的驅除策略,其是通過Ehcache的配置檔案來指定的。由於Ehcache不是本文描述的重點,這裡就不多贅述了,想了解更多關於Ehcache的資訊,請檢視我關於Ehcache的專欄。

@Caching

@Caching註解可以讓我們在一個方法或者類上同時指定多個Spring Cache相關的註解。其擁有三個屬性:cacheable、put和evict,分別用於指定@Cacheable、@CachePut和@CacheEvict。

   @Caching(cacheable = @Cacheable("users"), evict = { @CacheEvict("cache2"),

         @CacheEvict(value = "cache3", allEntries = true) })

   public User find(Integer id) {

      returnnull;

   }