SpringBoot學習筆記08——解決Cache快取同類中呼叫失敗問題
阿新 • • 發佈:2018-11-12
問題描述
今天遇到了一個問題,使用快取的情況下,如果在快取服務類方法中呼叫快取的方法會呼叫失敗,就是this.快取方法名,這樣使用就不會從快取中獲取資料,而是直接呼叫快取方法,錯誤示例程式碼如下:
package com.youyou.address.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * 這是一個測試快取service * * @author 劉朋 * <br/>date 2018-10-24 */ @Service public class CacheService { @Autowired private CacheService cacheService; /** * 查詢快取,快取的名字是testList,用key來標識 * @param key * @return */ @Cacheable(cacheNames = "testList" , key = "#key") public List<String> testCache(String key){ System.out.println("呼叫了快取方法"); List<String> list = new ArrayList<>(); list.add("a"); list.add(key); return list; } /** * 修改快取,快取的名字是testList,用key來標識 * @param key * @return */ @CachePut(cacheNames = "testList" , key = "#key") public List<String> testPutCache(String key){ List<String> stringList = testCache(key); List<String> list = new ArrayList<>(); list.add("1"); list.add(key); return list; } }
上述程式碼就存在問題,呼叫testPutCache()時,系統並不會去查詢testCache()方法快取的資料,而是直接呼叫testCache()方法。
讓我們測試一下:
public String testCache(){ //第一次中快取中查詢 List<String> test = cacheService.testCache("test"); //修改快取中的值 List<String> test2 = cacheService.testPutCache("test"); return ""; }
後臺輸出結果如下:
會輸出兩次“呼叫了快取方法”,顯然時快取的程式碼出現了問題。
後來我查閱了一下資料,明白了其中的緣由,簡單來講,在通過注入物件的形式呼叫方法時,spring會檢測到快取註解,會以aop的形式去執行方法,首先去快取中查詢,如果查詢到資料了,就不再執行改方法。如果時在方法中直接呼叫的話就不能使用aop進行判斷了,所以每次都會執行方法體。
解決方法
網上查到的解決方法時這樣的“SpringAOP 無法解決,需要使用 AspectJ 來解決!”
這個解決方式博主本人沒有去測試,而是想到了另一個方法簡單易用。
我的思路是:既然我們不能直接呼叫,那麼就用注入的方式來解決這個問題就可以了,呼叫方法的時候使用物件來呼叫不就沒有問題了嗎?
接下來帶著猜想博主進行了測試,測試程式碼如下:
package com.youyou.address.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 這是一個測試快取service
*
* @author 劉朋
* <br/>date 2018-10-24
*/
@Service
public class CacheService {
@Autowired
private CacheService cacheService;
/**
* 查詢快取,快取的名字是testList,用key來標識
* @param key
* @return
*/
@Cacheable(cacheNames = "testList" , key = "#key")
public List<String> testCache(String key){
System.out.println("呼叫了快取方法");
List<String> list = new ArrayList<>();
list.add("a");
list.add(key);
return list;
}
/**
* 修改快取,快取的名字是testList,用key來標識
* @param key
* @return
*/
@CachePut(cacheNames = "testList" , key = "#key")
public List<String> testPutCache(String key){
List<String> stringList = cacheService.testCache(key);
List<String> list = new ArrayList<>();
list.add("1");
list.add(key);
return list;
}
}
只是在呼叫testCache()方法時是通過物件進行呼叫的。
執行結果如下:
只打印了一次“呼叫了快取方法”
這說明博主的猜想是正確的。