詳解Spring Boot的RedisAutoConfiguration配置

华为云开发者联盟發表於2024-06-14

本文分享自華為雲社群《【Spring Boot 原始碼學習】RedisAutoConfiguration 詳解》,作者: Huazie。

引言

帶大家分析 Spring Boot 內建的有關 Redis 的自動配置類【RedisAutoConfiguration】。

1. Spring Data Redis

Spring Data Redis 是 Spring Data 家族的一部分,它提供了從 Spring 應用程式中輕鬆配置和訪問 Redis 的功能。

我們來看看官方介紹的特性:

  • 連線包作為多個 Redis 驅動程式( Lettuce 和 Jedis )的低階別抽象。
  • 將 Redis 驅動程式異常轉換為 Spring 的可移植資料訪問異常層次結構。
  • 提供各種 Redis 操作、異常轉換和序列化支援的 RedisTemplate。
  • 支援釋出訂閱(例如用於訊息驅動 POJO 的訊息監聽器容器)。
  • 支援 Redis Sentinel 和 Redis Cluster。
  • 使用 Lettuce 驅動程式的響應式 API。
  • 支援 JDK、String、JSON和 Spring 物件 / XML 對映序列化器。
  • 在 Redis 上實現 JDK 集合。
  • 支援原子計數器類。
  • 支援排序和管道功能。
  • 專用於 SORT、SORT/GET模式和支援返回批次值的功能。
  • 為 Spring 快取抽象提供 Redis 實現。
  • 自動實現 Repository 介面,包括使用 @EnableRedisRepositories 支援自定義查詢方法。
  • 對儲存庫提供 CDI 支援。

在 Spring Data Redis 中,我們可以直接使用 RedisTemplate 及其相關的類來操作 Redis。雖然 RedisConnection 提供了接受和返回二進位制值(位元組陣列)的低階方法,但 RedisTemplate 負責序列化和連線管理,使使用者可以無需處理這些細節。

RedisTemplate 還提供了操作檢視(按照 Redis 命令參考進行分組),這些檢視提供了豐富、通用的介面,用於針對特定型別或特定鍵進行操作(透過 KeyBound 介面實現),如下表所示:

詳解Spring Boot的RedisAutoConfiguration配置

下面我們來看看相關的 Spring 配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>
  <!-- redis 模板定義 -->
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnFactory"/>

</beans>

一旦配置完成,Redis 模板就是執行緒安全的,並且可以在多個例項之間重用。

RedisTemplate 使用基於 Java 的序列化器進行大部分操作。也就意味著透過模板寫入或讀取的任何物件都是透過 Java 進行序列化和反序列化的。

我們也可以更改模板上的序列化機制,可以新增如下配置:

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="redisConnectionFactory"/>
    <property name="keySerializer">
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    </property>
    <property name="valueSerializer">
        <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
    </property>
    <property name="hashKeySerializer">
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    </property>
    <property name="hashValueSerializer">
        <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
    </property>
</bean>

而 Redis 模組提供了幾個序列化器的實現,有關這些實現大家可以檢視 org.springframework.data.redis.serializer 包。

cke_118.png

還可以將任何序列化程式設定為 null,並透過設定 enableDefaultSerializer 屬性為 false 來使用RedisTemplate 與原始位元組陣列一起使用。

注意: 模板要求所有鍵都不為空。但是,只要底層序列化程式接受值,值就可以為空。

下面我們可以注入 RedisTemplate,並呼叫 RedisTemplate 的方法進行儲存、查詢、刪除等操作。

@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 儲存資料
redisTemplate.opsForValue().set("key", "value");
// 查詢資料
Object value = redisTemplate.opsForValue().get("key");
// 刪除資料
redisTemplate.delete("key");

對於需要特定模板檢視的情況,宣告檢視作為依賴項並注入模板。容器會自動執行轉換,消除opsFor[X] 呼叫,如下所示的示例:

public class Example {    
    // inject the template as ListOperations
    @Resource(name="redisTemplate")
    private ListOperations<String, String> listOps;
    
    public void addLink(String userId, URL url) {
      listOps.leftPush(userId, url.toExternalForm());
    }
}

當然 Spring Data Redis 肯定不止上述這些,有需要深入瞭解的讀者們,請看如下:

參考: Spring Data Redis 官方文件

2. RedisAutoConfiguration

那麼 Spring Data Redis 的 RedisTemplate 的自動配置在 Spring Boot 是如何實現的呢?

Spring Boot 是透過內建的 RedisAutoConfiguration 配置類來完成這一功能。下面我們具體分析一下:

注意: 以下涉及 Spring Boot 原始碼 均來自版本 2.7.9,其他版本有所出入,可自行檢視原始碼。

2.1 載入自動配置元件

從之前的《【Spring Boot 原始碼學習】自動裝配流程原始碼解析(上)》中,我們知道 Spring Boot 內部針對自動配置類,會讀取如下兩個配置檔案:

  • META-INF/spring.factories
  • META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

cke_119.png

實際上 在 Spring Boot 2.7.9 版本中, Spring Boot 自己內部的 META-INF/spring.factories 中有關自動配置的註冊類的配置資訊已經被去除掉了,不過其他外圍的 jar 中可能有自己的 META-INF/spring.factories 檔案,它裡面也有關於自動配置註冊類的配置資訊;

而 Spring Boot 內建的 RedisAutoConfiguration 配置類,則是配置在上述的第二個配置檔案 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中。

cke_120.png

2.2 過濾自動配置元件

上述自動配置載入完之後,就來到了 《【Spring Boot 原始碼學習】自動裝配流程原始碼解析(下)》 介紹的 過濾自動配置元件 邏輯。

這部分資料對應的配置內容在 META-INF/spring-autoconfigure-metadata.properties 檔案中:

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration=
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.ConditionalOnClass=org.springframework.data.redis.core.RedisOperations

顯然這裡涉及到了 ConditionalOnClass 註解,我們翻看 RedisAutoConfiguration 配置類的原始碼,如下:

@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 。。。
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 。。。
    }

}

2.2.1 涉及註解

我們先來看看上述 RedisAutoConfiguration 配置類涉及到的註解,如下:

  • @AutoConfiguration : 該類是一個自動配置類,Spring Boot 會根據專案中的依賴自動配置這個類的例項。
  • @ConditionalOnClass(RedisOperations.class) :只有在專案中引入了 RedisOperations 類(通常由 spring-data-redis 庫提供)的情況下,才會載入這個配置類。
  • @EnableConfigurationProperties(RedisProperties.class) :啟用RedisProperties 類作為配置屬性。這樣,我們就可以在 application.properties 或application.yml 檔案中定義 Redis 的相關配置。
  • @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) :匯入註解,表示匯入 LettuceConnectionConfiguration 和 JedisConnectionConfiguration 這兩個類。這兩個類通常用於配置 Redis 連線的具體實現,例如使用 Lettuce 還是 Jedis 等。
  • @Bean :用於宣告一個方法建立的物件是一個 Spring 管理的 Bean。Spring 容器會自動管理這個 Bean 的生命週期,包括依賴注入、初始化和銷燬等。
  • @ConditionalOnMissingBean :只有在當前 Spring 容器中不存在指定型別的 Bean 時,才會執行被註解的方法。這樣可以用於確保在需要的時候才建立某個 Bean,避免重複建立。
  • @ConditionalOnSingleCandidate:只有在當前上下文中存在且只有一個指定型別的 bean 候選者時,才會建立這個 bean。

2.2.2 RedisProperties

其中 RedisProperties 類的屬性值對應著 application.yml 或 application.properties 中的配置,透過註解@ConfigurationProperties(prefix = "spring.redis") 實現的屬性注入。

有關屬性注入的內容後續筆者會另外介紹,我們先來看看RedisProperties 類相關的部分原始碼 和 對應的配置引數:

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

    // 。。。

    // Redis 伺服器主機地址.
    private String host = "localhost";
    
    // 。。。

    // Redis 伺服器的埠
    private int port = 6379;

    private Sentinel sentinel;

    private Cluster cluster;

    private final Jedis jedis = new Jedis();

    private final Lettuce lettuce = new Lettuce();

    // Redis 連線池配置
    public static class Pool {
        // 。。。
    }
    // Redis 叢集配置
    public static class Cluster {
        // 。。。
    }
    // Redis 哨兵配置
    public static class Sentinel {
        // 。。。
    }
    // Jedis 客戶端配置
    public static class Jedis {

        // Jedis 連線池配置
        private final Pool pool = new Pool();
    }
    // Lettuce 客戶端配置
    public static class Lettuce {
        // Lettuce 連線池配置
        private final Pool pool = new Pool();

        private final Cluster cluster = new Cluster();
    }
}

然後在 application.properties 中,我們就可以新增類似如下的配置:

# Redis 單機配置
spring.redis.host=127.0.0.1
spring.redis.port=31113

# Redis 叢集配置
# nodes屬性是Redis叢集節點的地址和埠,用逗號分隔。
spring.redis.cluster.nodes=192.168.1.1:7000,192.168.1.2:7001,192.168.1.3:7002
# max-redirects屬性是最大重定向次數,用於處理節點故障的情況。
spring.redis.cluster.max-redirects=3

# mymaster是哨兵模式下的主節點名稱。
spring.redis.sentinel.master=mymaster
# nodes是哨兵模式下的從節點地址和埠。
spring.redis.sentinel.nodes=192.168.1.1:26379,192.168.1.2:26379,192.168.1.3:26379

# ...其他配置省略

2.3 redisTemplate 方法

先來看看 redisTemplate 方法的原始碼【Spring Boot 2.7.9】:

@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

上述邏輯表示只有在當前上下文中不存在名為 "redisTemplate" 的 Bean 時,才會建立一個名為 redisTemplate 的 RedisTemplate Bean,並將其與一個可用的 Redis 連線工廠關聯起來。

2.4 stringRedisTemplate 方法

我們再來看看 stringRedisTemplate 方法的原始碼【Spring Boot 2.7.9】:

@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
    return new StringRedisTemplate(redisConnectionFactory);
}

上述邏輯也好理解,它表示只有在當前上下文中不存在名為 "stringRedisTemplate" 的 Bean 時,才會建立一個名為stringRedisTemplate的 StringRedisTemplate Bean,並將其與一個可用的 Redis 連線工廠關聯起來。

StringRedisTemplate 是 RedisTemplate 的子類,專門用於處理字串型別的資料。

StringRedisTemplate 使用的是 StringRedisSerializer,它在存入資料時會將資料先序列化成位元組陣列。

預設情況下,StringRedisTemplate 採用的序列化策略有兩種:

  • String 的序列化策略,
  • JDK 的序列化策略。

總結

本篇我們深入分析了 RedisAutoConfiguration 配置類的相關內容,進一步加深了對自動配置裝配流程的瞭解。

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章