SpringBoot的EnableCaching簡述

2023-03-28 18:02:03

Spring Boot中的EnableCaching簡述

spring boot中自帶有資料快取機制,主要通過其org.springframework.cache包下的各種類來實現。

EnableCaching

@EnableCaching是啟用快取的註解,標註在任何一個可自動注入的類上即可開啟。

Cacheable

@Cacheable是一個標註與類與方法上的註解,用於表示此類或此方法需要使用快取機制。當類與方法上都有時,採用 就近原則

@Cacheable註解中,有一些常用引數可以進行設定:

  • valuecacheNames - 表示繫結的快取名稱。這裡的快取指的是單個的快取記憶體,並不是最終的鍵值對快取物件。
  • 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

CachePut

將方法返回值存入到快取中,一般情況下是用在更新操作中,並於CacheableCacheEvict配合使用。

CacheEvict

清除快取值,一般用在刪除或更新操作中,並於CacheableCachePut配合使用。

並且在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快取存取器中取出key123的快取數值,沒有則會呼叫方法並進行快取。

存取put介面時,會將c快取存取器key123的快取值改為hello put,沒有則進行快取。

存取evict介面時,會將c快取存取器key123的快取值刪除,此時存取hello介面會重新呼叫方法並進行快取。

CacheConfig

@CacheConfig作為類上的註解,目的是為了統一設定其下的方法快取引數,並設定共用快取名。

  • cacheNames - 共用快取名陣列。設定後表示此類下的方法快取會依次從這些快取存取器中取值,如果有,則取用快取值;若沒有則呼叫方法取值,並快取值到設定的所有快取存取器中。

CacheManager

快取管理器介面,用來做快取管理的類。一般我們需要自定義快取策略時,就是從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註解中的valuecacheName引數。
  • getCacheNames - 獲取類中所有快取的名稱集合。這主要是為了Spring內部的統一管理需要。
    因為 Spring採用了預設替補策略,所以我們使用@Component或是通過@Bean自動注入後,預設的快取管理器就會切換成我們自定義的。如果我們自定義了兩個的話,可以通過@Primary來設定預設管理器。

Cache

快取存取器,用來管理快取鍵值對的基本單元。
為了能對不同的快取採用不同的存取策略,我們可以客製化不同的Cache,並通過自定義的CacheManagergetCache方法返回對應的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,並對每次快取值的獲取都進行了控制檯輸出。

KeyGenerator

快取key生成器,用於自定義規則快取key的生成。
其介面的方法只有一個:

public interface KeyGenerator {
    Object generate(Object target, Method method, Object... params);
}

一目瞭然,通過呼叫的目標物件、目標方法與方法入參進行key的生成。這裡不做過多贅述。
不過需要注意的是,由於不同類可能有同名同引數的方法,這裡建議加上target.getClass().getName()來作為標記,避免出現不希望的快取對映。