SpringBoot Redis 實踐指南

前言

SpringBoot Cache 是一個很好的快取框架,可以兼容多種快取實現,數據量較大的情況下,Redis 應該是最多被使用的。

本文重點介紹 SpringBoot 和 Redis 整合使用的關鍵流程,並對其中的核心要點給出說明,且附上相應的官方文檔鏈接便於參考。

添加 Maven 依賴

在項目 pom.xml 中添加如下配置:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <version>${spring-boot.version}</version>
</dependency>

啟用快取

在項目 啟動類 中添加如下注解:

@EnableCaching

配置快取

配置 Redis 連接資訊

Redis 連接資訊包括地址、埠、超時時間(秒)和連接池等,可以根據需要選取若干配置即可。

在項目 application.yml 中添加如下配置:

spring:
  redis:
    host: ${host}
    port: ${port}
    timeout: 3000
    lettuce:
      pool:
        enabled: true
        max-active: 30

SpringBoot 默認使用的 Redis 客戶端是 lettuce,不是 Jedis。如果需要使用連接池的話,還需要額外添加一個 Maven 依賴:

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
  <version>${commons-pool2.version}</version>
</dependency>

Redis 連接配置屬性參考,注意屬性前綴為 spring.redis.*。

配置快取資訊

SpringBoot 支援多個不同名稱的快取,快取名稱需要預先配置,還可以指定快取的過期時間。對於 Redis 而言,某個名稱的快取實際上就是 Redis 中一個或多個以該名稱為前綴的 Key,快取的過期時間指的就是這部分 Key 的過期時間。

在項目 application.yml 中添加如下配置:

spring:
  cache:
    cache-names: "cache1,cache2"
    redis:
      time-to-live: "10m"

快取配置屬性參考,注意屬性前綴為 spring.cache.redis.*。

默認情況下,所有快取的過期時間都是一樣的。如果需要對不同的快取設置不同的過期時間,可以自己擴展實現,參考官方示例

使用快取

@Cacheable

SpringBoot Cache 可以幫助我們自動快取某個方法的結果(返回值),使用時我們只需要在方法上面添加註解 @Cacheable,並且指定快取名稱即可:

@Cacheable(cacheNames = {"cos::url"})
public String generatePresignedUrl(String name) {
  return ...;
}

快取名稱為 cos::url,調用方法 generatePresignedUrl 時,SpringBoot Cache 會自動檢查 Redis 中是否已經快取過該方法的結果,如果已經快取過,則直接使用快取中的結果返回,該方法不會執行;如果沒有快取過,會執行該方法獲取結果,快取結果之後再返回給調用者。

Caching

Key Generation

Redis 檢查或快取結果時均需要一個 Key,SpringBoot Cache 使用 快取名稱(CacheName,如:cos::url)和 參數值(ParameterValue,如:value1)生成 Key,規則如下:

  • 如果方法沒有參數,Key 為 CacheName::SimpleKey [],即:cos::url::SimpleKey [];
  • 如果方法只有一個參數,Key 為 CacheName::ParameterValue,即:cos::url::value1;
  • 如果方法有兩個或兩個以上的參數,Key 為 CacheName::SimpleKey [ParameterValue1,ParameterValue2,…],即:cos::url::SimpleKey [value1,value2];

Default Key Generation

sync

sync 是註解 @Cacheable 的一個屬性,值可以是 true 或 false:

如果 sync = false(默認),多執行緒環境下調用方法 generatePresignedUrl 時,Redis 沒有快取結果的情況下,方法可能會被執行多次;
如果 sync = true,Redis 沒有快取結果的情況下,方法 generatePresignedUrl 只會被執行一次。

Conditional Caching

condition

condition 是註解 @Cacheable 的一個屬性,它的值是一個 SpEL 表達式,表達式的計算結果可以是 true 或 false:

如果表達式的計算結果是 true,表示快取方法結果;
如果表達式的計算結果是 false,表示不快取方法結果;

Conditional Caching

SpEL 表達式可以使用方法的參數值,也可以調用該方法所在 Bean 的其它方法,如:

#name.length() < 32

方法參數 name 的參數值長度小於 32 時,方法結果才會被快取;

condition = "#root.target.check(#name)"

check() 必須是公開的(public),且返回值必須是布爾類型(Boolean);只有 check() 返回值為 true 時,方法結果才會被快取。

Available Caching SpEL Evaluation Context

使用限制

如果方法 generatePresignedUrl 被位於一個 Bean 的其它方法調用時,快取不會生效;也就是說,方法 generatePresignedUrl 必須被其它 Bean 的方法調用時,快取才會生效。原因主要是和 Spring 的代理機制有關,詳情可以參考:Spring Cache @Cacheable – not working while calling from another method of the same bean

SpringBoot Cache 還支援其它註解,可以參考 Declarative Annotation-based Caching

RedisTemplate

如果我們需要自己實現快取邏輯,SpringBoot Cache 提供了一個封裝 Redis 常用操作的工具模板類:RedisTemplate,並且會創建好它的實例,使用時直接注入即可:

@Autowired
private StringRedisTemplate template;

@Autowired
private RedisTemplate<String, String> template2;

@Autowired
private RedisTemplate<String, Integer> template3;

RedisTemplate 支援泛型,我們可以根據自己的需求注入一個或多個實例;如果鍵值的類型都是 String,可以直接使用 StringRedisTemplate

結語

SpringBoot 整合 Redis 使用時,如果僅僅是需要讀取或快取數據,直接使用註解的方式相較於使用 RedisTemplate 的方式,可以避免大量的快取冗餘程式碼,更多地關注業務邏輯;但是缺點也比較明顯,操控性比較差。實際使用時,可以靈活結合兩者,優先使用註解方式;註解方式受限時,再結合 RedisTemplate 作為補充。