spring boot中自帶有資料快取機制,主要通過其org.springframework.cache
包下的各種類來實現。
@EnableCaching
是啟用快取的註解,標註在任何一個可自動注入的類上即可開啟。
@Cacheable
是一個標註與類與方法上的註解,用於表示此類或此方法需要使用快取機制。當類與方法上都有時,採用 就近原則。
在@Cacheable
註解中,有一些常用引數可以進行設定:
value
與cacheNames
- 表示繫結的快取名稱。這裡的快取指的是單個的快取記憶體,並不是最終的鍵值對快取物件。key
- 表示快取物件的 key,這個才是最終的快取鍵值對的 key。這裡的引數需要使用 SpEL表示式。keyGenerator
- 表示用於生成此方法 快取key的類。與key
引數只能選擇一個新增,否則會丟擲IllegalStateException
異常。cacheManager
- 指定快取管理器。這個後面再細說。condition
- 快取的條件。支援SpEL,當快取條件滿足時,才會進入快取取值模式。unless
- 排除的條件。支援SpEL,當排除的條件滿足時,會直接呼叫方法取值。sync
- 非同步快取模式。是否採用非同步的方式,在方法取值時非同步快取。預設false
,在快取完成後才返回值。一般情況下,可以這樣使用:
@RestController
@RequestMapping("cache")
@Cacheable(value = "cache", sync = true)
public class CacheController {
@Cacheable(value = "hello", sync = true, keyGenerator = "myKeyGenerator")
@GetMapping("hello")
public String hello(String name) {
System.out.println("name - " + name);
return "hello " + name;
}
@GetMapping("hello2")
public String hello2(@RequestParam(defaultValue = "1") Integer size, @RequestParam(defaultValue = "world") String name) {
System.out.println("name - " + name);
return "hello " + name;
}
}
CacheController
被標記上了@Cacheable(value = "cache", sync = true)
,表示其下的方法預設使用名為cache
的快取存取器,並採用非同步的方式進行快取處理。hello
方法上同樣新增了@Cacheable(value = "hello", sync = true, keyGenerator = "myKeyGenerator")
,使得hello
方法使用了獨立的快取設定,並通過myKeyGenerator
的策略來生成 快取key。將方法返回值存入到快取中,一般情況下是用在更新操作中,並於Cacheable
與CacheEvict
配合使用。
清除快取值,一般用在刪除或更新操作中,並於Cacheable
與CachePut
配合使用。
並且在CacheEvict註解中,多了兩個引數:
allEntries
- 清除當前value
下的所有快取。beforeInvocation
- 在方法執行前清除快取。範例程式碼範例如下:
@Cacheable(value = "c", key = "123")
@GetMapping("hello")
public String hello(String name) {
System.out.println("name - " + name);
return "hello " + name;
}
@GetMapping("/put")
@CachePut(value = "c", key = "123")
public String put() {
return "hello put";
}
@GetMapping("/evict")
@CacheEvict(value = "c", key = "123")
public String evict() {
return "hello put";
}
上述程式碼中,存取hello
介面時,會從c快取存取器中取出key為123
的快取數值,沒有則會呼叫方法並進行快取。
存取put
介面時,會將c快取存取器中key為123
的快取值改為hello put
,沒有則進行快取。
存取evict
介面時,會將c快取存取器中key為123
的快取值刪除,此時存取hello
介面會重新呼叫方法並進行快取。
@CacheConfig
作為類上的註解,目的是為了統一設定其下的方法快取引數,並設定共用快取名。
cacheNames
- 共用快取名陣列。設定後表示此類下的方法快取會依次從這些快取存取器中取值,如果有,則取用快取值;若沒有則呼叫方法取值,並快取值到設定的所有快取存取器中。快取管理器介面,用來做快取管理的類。一般我們需要自定義快取策略時,就是從CacheManager
來入手的。
直接上範例:
@Component
public class MyCacheManager implements CacheManager, InitializingBean {
private final Map<String, Cache> cacheMap;
public MyCacheManager() {
cacheMap = new HashMap<>();
}
@Override
public Cache getCache(String name) {
System.out.println("正在獲取快取 - " + name);
return cacheMap.computeIfAbsent(name, MyCache::new);
}
@Override
public Collection<String> getCacheNames() {
return cacheMap.keySet();
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("say something!");
}
}
CacheManager
有兩個方法需要被實現:
getCache(String)
- 獲取快取存取器。這裡的name
其實就對應了@Cacheable
註解中的value
與cacheName
引數。getCacheNames
- 獲取類中所有快取的名稱集合。這主要是為了Spring
內部的統一管理需要。@Component
或是通過@Bean
自動注入後,預設的快取管理器就會切換成我們自定義的。如果我們自定義了兩個的話,可以通過@Primary
來設定預設管理器。快取存取器,用來管理快取鍵值對的基本單元。
為了能對不同的快取採用不同的存取策略,我們可以客製化不同的Cache
,並通過自定義的CacheManager
的getCache
方法返回對應的Cache
。
舉個例子:
public final static class MyCache extends ConcurrentMapCache {
public MyCache(String name) {
super(name);
}
@Override
public <T> T get(Object key, Class<T> type) {
System.out.println("正在讀取 - " + key);
return super.get(key, type);
}
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
System.out.println("正在讀取 - " + key);
return super.get(key, valueLoader);
}
@Override
public ValueWrapper get(Object key) {
System.out.println("正在讀取 - " + key);
return super.get(key);
}
}
這裡的MyCache
整合了ConcurrentMapCache
,並對每次快取值的獲取都進行了控制檯輸出。
快取key生成器,用於自定義規則快取key的生成。
其介面的方法只有一個:
public interface KeyGenerator {
Object generate(Object target, Method method, Object... params);
}
一目瞭然,通過呼叫的目標物件、目標方法與方法入參進行key的生成。這裡不做過多贅述。
不過需要注意的是,由於不同類可能有同名同引數的方法,這裡建議加上target.getClass().getName()
來作為標記,避免出現不希望的快取對映。