? ? ? ? SpringBoot集成Redis的教程網上很多,總體來說就是三個步驟:添加依賴、修改配置文件、自定義Redis配置類(自定義序列化器),具體步驟可自行搜索,本文主要解惑集成中的常見疑問。
1,選擇什么依賴?
? ? ? ? SpringBoot集成Redis共有三種依賴可選:spring-boot-starter-data-redis,spring-data-redis,redisson-spring-boot-start。先說結果:
????????優先選擇 ??spring-boot-starter-data-redis??,快速實現緩存功能,避免過度設計。
????????高并發或分布式系統??,直接使用 ??redisson-spring-boot-starter??,其內置的分布式鎖、限流器可顯著降低復雜度。
? ? 1),spring-boot-starter-data-redis(官方推薦)
????????定位??:Spring Boot官方提供的開箱即用方案,封裝了Spring Data Redis的核心功能。
??????????底層客戶端??:默認使用Lettuce(基于Netty的非阻塞I/O),也可切換為Jedis(傳統阻塞式I/O)。
??????????核心優勢??:
??????????????????自動化配置??:僅需配置spring.redis.host/port等參數即可自動初始化連接池和RedisTemplate。
??????????????????統一操作接口??:提供RedisTemplate和StringRedisTemplate,支持字符串、哈希、列表等數據結構操作。
??????????????????與Spring生態無縫集成??:支持Spring Cache抽象、事務管理和Repository模式。
??????????局限性??:
????????????????高級功能(如分布式鎖、限流)需自行實現(如Lua腳本或第三方庫)。
????????????????默認序列化方式為JDK序列化(可讀性差),需手動配置JSON序列化。
? ? ? ? 適用場景:簡單緩存、基礎數據操作
????????性能:中等(依賴Lettuce/Jedis)
????????高級功能:需自行實現
? ? 2),spring-data-redis
????????非SpringBoot項目(如Springmvc,Spring)引入的依賴,不包含客戶端、連接池,需手動配置連接工廠。spring-boot-starter-data-redis??已包含?? spring-data-redis。
? ? 3),redisson-spring-boot-start(分布式redis依賴)
????????定位??:Redisson提供的增強方案,支持分布式對象和高級分布式功能。
????????核心優勢??:
????????????????開箱即用的分布式工具??:內置分布式鎖(支持自動續期)、信號量、限流器(RRateLimiter)、延遲隊列等。
????????高性能本地緩存??:通過RLocalCachedMap減少網絡IO,緩存命中率提升顯著(壓測可達百萬級QPS)。
????????異步與響應式支持??:基于Netty的非阻塞通信,支持RBatch批量操作提升吞吐量。
????????局限性??:
????????????????學習成本高,需理解分布式對象(如RMap、RBucket)的API設計。
????????????????部分簡單操作(如基礎字符串存取)代碼量略多于RedisTemplate。
????????適用場景:分布式鎖、限流、高并發系統
????????性能:高于spring-boot-starter-data-redis,基于Netty異步+本地緩存優化
????????高級功能:內置分布式工具
2,多模塊怎么將Redis配置文件和配置類獨立出來,避免各模塊重復工作?
- 微服務系統可將做配置中心;
- 非微服務系統可設置一個base-module模塊,在需要使用redis的模塊的pom文件中引入該模塊的依賴。
3,為什么要配置Redis連接池,其作用是什么,有哪些連接池可選?
????????Redis連接池(Pool)是指客戶端連接池,是為了管理客戶端(如Jedis或Lettuce)與Redis服務器之間的網絡連接而存在的。
????????Redis服務端可簡單理解成單線程應用(實際非單線程,參考文章Redis-02 單線程與高性能-CSDN博客),無連接池一說。
????????Redis客戶端(即自己的程序,是多線程的)通常是Springboot應用,是多線程的web服務,可同時處理上萬用戶請求,可能產生并發的Redis操作請求,配置客戶端連接池,可在客戶端請求Redis時,減少客戶端連接Redis服務器帶來的創建、銷毀等開銷(如建立tcp連接、tcp斷開、認證等)。
4,RedisTemplate和StringRedisTemplate是什么,有什么區別,生產環境一般怎么使用?
? ? ? ? 科普:
????????它們都是Spring Data Redis提供的核心工具類,用于在Java應用中與Redis服務器進行交互,封裝了底層的連接管理、序列化/反序列化等復雜操作,讓你可以用面向對象的方式操作Redis。
? ? ? ? 區別:
????????核心的區別是默認的序列化器不同。序列化器決定了Java對象如何轉換成二進制數據存入Redis,以及如何從二進制數據變回Java對象。可以把 StringRedisTemplate 看作是 RedisTemplate<String, String> 的一個特例,它強制要求鍵和值都是字符串,并使用字符串序列化器。
StringRedisTeplate | RedisTeplate | |
---|---|---|
key序列化器 | StringRedisSerializer | JdkSerializationRedisSerializer |
value序列化器 | StringRedisSerializer | JdkSerializationRedisSerializer |
存儲結果 | 可讀的字符串。set("name", "Alice") 在Redis中存的就是 "Alice" | 不可讀的JDK序列化字節碼。存進去是亂碼,如 \xac\xed\x00\x05t\x00\x04name |
使用場景 | 處理字符串和文本結構的數據 | 處理復雜的Java對象(但需要配置序列化器) |
? ? ? ? 生產環境怎么使用:
????????優先使用 StringRedisTemplate 來處理字符串鍵值對。
????????對于需要存儲復雜Java對象的場景,會配置一個專門化的 RedisTemplate(例如 RedisTemplate<String, Object>),并將其值的序列化器改為JSON序列化器(如 Jackson2JsonRedisSerializer 或 GenericJackson2JsonRedisSerializer)。
????????絕對要避免使用默認配置(JDK序列化)的 RedisTemplate!
5,生產環境怎么設置RedisTemplate的序列化器?
? ? ? ? 以常用的GenericJackson2JsonRedisSerializer序列化器為例,生產環境各種配置方式如下:
? ? ? ? 1),簡單快速使用設置
@Configuration
public class RedisTemplateConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);// 設置Key和HashKey的序列化器為StringRedisSerializertemplate.setKeySerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());// 設置Value和HashValue的序列化器為GenericJackson2JsonRedisSerializer (JSON格式)GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();template.setValueSerializer(jsonSerializer);template.setHashValueSerializer(jsonSerializer);template.afterPropertiesSet();return template;}}
? ? ? ? 上述序列化器設置完成即可使用Redis,但是有個弊端,假如存放的是對象,如User(id, name, age, sex, position),在Redis中是Json數據格式,web端獲取User時,返回的是LinkedHashMap<String, Object>,無法直接強轉成User對象。同樣,如果存放的是List<User>,在Redis中是Json數組,返回則是List<LinkedHashMap>。
? ? ? ? 2),優化序列化設置
@Configuration
public class RedisTemplateConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);// 設置Key和HashKey的序列化器為StringRedisSerializertemplate.setKeySerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());// 設置Value和HashValue的序列化器為GenericJackson2JsonRedisSerializer (JSON格式),并配置返回序列化類型// 創建 ObjectMapper 并配置多態類型支持/*** 作用:* 這行代碼配置 ObjectMapper 在序列化 JSON 時,自動嵌入類的類型信息。* 這樣在反序列化時,Jackson 就能根據這些信息準確地還原成原始對象類型,而不是簡單的 LinkedHashMap。*/ObjectMapper objectMapper = new ObjectMapper();objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, // 非嚴格驗證,更嚴謹的使用方式是將類型驗證器LaissezFaireSubTypeValidator替換為TypeValidatorObjectMapper.DefaultTyping.NON_FINAL,JsonTypeInfo.As.PROPERTY);GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);template.setValueSerializer(jsonSerializer);template.setHashValueSerializer(jsonSerializer);template.afterPropertiesSet();return template;}}
? ? ? ? 如上述代碼,多添加了ObjectMapper,并激活了如下幾個配置:
- LaissezFaireSubTypeValidator.instance:配置了對象的類型驗證器,允許反序列化任何類型(有安全風險,但操作簡單方便開發)。
- ObjectMapper.DefaultTyping.NON_FINAL:指定哪些類型需要包含類型信息。NON_FINAL:所有非final類都需要包含類型信息。可選項還有:NON_CONCRETE_AND_ARRAYS(非具體類型和數組), EVERYTHING(所有類型)
- JsonTypeInfo.As.PROPERTY:指定類型在Redis中如何潛入到JSON里。PROPERTY:作為單獨屬性添加到JSON中。可選項還有:WRAPPER_ARRAY(包裝為數組),WRAPPER_OBJECT(包裝為對象)。
? ? ? ? 添加如上反序列化配置后,假如存放的是List<User>,則Redis中存儲格式如下:
["java.util.ArrayList",[["com.example.User",{"id":1,"name":"張三"}],["com.example.User", {"id":2,"name":"李四"}]]
]
? ? ? ? 客戶端獲取數據時,反序列化就知道該對象是List,內部對象是User,這樣結果就可以直接強轉。
? ? ? ? 3),反序列化類型驗證器
package com.mango.basedata.common;import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisTemplateConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);// 設置Key和HashKey的序列化器為StringRedisSerializertemplate.setKeySerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());// 設置Value和HashValue的序列化器為GenericJackson2JsonRedisSerializer (JSON格式),并配置返回序列化類型// 創建 ObjectMapper 并配置多態類型支持/*** 作用:* 這行代碼配置 ObjectMapper 在序列化 JSON 時,自動嵌入類的類型信息。* 這樣在反序列化時,Jackson 就能根據這些信息準確地還原成原始對象類型,而不是簡單的 LinkedHashMap。*/ObjectMapper objectMapper = new ObjectMapper();// 創建更安全的類型驗證器(白名單機制)BasicPolymorphicTypeValidator typeValidator = BasicPolymorphicTypeValidator.builder().allowIfSubType("com.example.models.entity").allowIfSubType("java.util.ArrayList").allowIfSubType("java.util.HashMap").build();objectMapper.activateDefaultTyping(typeValidator,ObjectMapper.DefaultTyping.NON_FINAL,JsonTypeInfo.As.PROPERTY);GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);template.setValueSerializer(jsonSerializer);template.setHashValueSerializer(jsonSerializer);template.afterPropertiesSet();return template;}}