Spring Boot :Redis 多模式 + 多客戶端兼容配置指南(附完整代碼)
引言
在實(shí)際項(xiàng)目開(kāi)發(fā)中,Redis的部署模式往往因環(huán)境而異:開(kāi)發(fā)環(huán)境用單機(jī)版(輕量化)、測(cè)試環(huán)境用哨兵模式(高可用驗(yàn)證)、生產(chǎn)環(huán)境用集群模式(高可用 + 高并發(fā));同時(shí),不同團(tuán)隊(duì)對(duì)Redis客戶端的選擇也存在差異(Jedis輕量直觀,Lettuce非阻塞高性能)。
Redis 三大部署模式
部署模式 | 適用場(chǎng)景 | 核心特點(diǎn) |
單機(jī)模式 | 開(kāi)發(fā) / 本地測(cè)試 | 單實(shí)例,無(wú)高可用,配置簡(jiǎn)單 |
哨兵模式( | 測(cè)試環(huán)境 / 中小流量生產(chǎn) | 1 主 N 從 + 哨兵節(jié)點(diǎn),自動(dòng)故障轉(zhuǎn)移,保障高可用 |
集群模式( | 高并發(fā)生產(chǎn)環(huán)境 | 多主多從,數(shù)據(jù)分片存儲(chǔ),支持水平擴(kuò)展 |
主流客戶端
Jedis:基于阻塞IO實(shí)現(xiàn),API直觀,適合簡(jiǎn)單場(chǎng)景;需通過(guò)連接池管理連接,避免頻繁創(chuàng)建銷毀。Lettuce:基于Netty非阻塞IO實(shí)現(xiàn),線程安全,支持異步操作,性能更優(yōu);Spring Boot 2.x后默認(rèn)使用。
實(shí)現(xiàn)方案
依賴配置
<!-- Spring Data Redis核心依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- 排除默認(rèn)Lettuce(若需保留Lettuce,可刪除此exclusion) -->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 1. 引入Jedis客戶端(若用Lettuce,無(wú)需此依賴,恢復(fù)上方Lettuce即可) -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- 2. 連接池依賴(Jedis和Lettuce均需) -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 3. JSON序列化依賴(用于RedisTemplate存儲(chǔ)對(duì)象) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>配置文件
spring:
redis:
# 1. 核心切換參數(shù)
client-type: jedis # 客戶端類型:jedis / lettuce
mode: standalone # 部署模式:standalone(單機(jī)) / cluster(集群) / sentinel(哨兵)
password: your-redis-pwd # Redis密碼(可選,所有模式共用)
timeout: 5000ms # 連接超時(shí)時(shí)間(毫秒)
# 2. Jedis連接池配置(client-type=jedis時(shí)生效)
jedis:
pool:
max-active: 16 # 最大連接數(shù)(根據(jù)業(yè)務(wù)調(diào)整)
max-idle: 8 # 最大空閑連接
min-idle: 4 # 最小空閑連接
max-wait: 3000ms # 最大阻塞等待時(shí)間(-1表示無(wú)限制)
# 3. Lettuce連接池配置(client-type=lettuce時(shí)生效,需注釋Jedis配置)
# lettuce:
# pool:
# max-active: 16
# max-idle: 8
# min-idle: 4
# max-wait: 3000ms
# 4. 單機(jī)模式配置(mode=standalone時(shí)生效)
standalone:
host: 192.168.1.100 # Redis單機(jī)IP
port: 6379 # Redis單機(jī)端口(默認(rèn)6379,本文示例用20516)
# 5. 集群模式配置(mode=cluster時(shí)生效)
cluster:
nodes: # 集群所有節(jié)點(diǎn)(IP:端口)
- 134.188.194.30:20516
- 134.188.194.32:20516
- 134.188.194.30:20517
- 134.188.194.32:20517
- 134.188.194.30:20518
- 134.188.194.32:20518
max-redirects: 3 # 集群最大重定向次數(shù)(默認(rèn)3)
# 6. 哨兵模式配置(mode=sentinel時(shí)生效)
sentinel:
master: mymaster # 哨兵監(jiān)控的主節(jié)點(diǎn)名稱
nodes: # 哨兵節(jié)點(diǎn)列表(IP:端口)
- 134.188.194.30:26379
- 134.188.194.32:26379核心配置類
核心思路:利用 Spring 的@ConditionalOnProperty注解,根據(jù)client-type和mode的取值,動(dòng)態(tài)激活對(duì)應(yīng)的配置Bean,最終統(tǒng)一返回RedisConnectionFactory(Spring Data Redis 的核心連接接口),確保RedisTemplate無(wú)感知適配。
/**
* Redis多模式(單機(jī)/集群/哨兵)與多客戶端(Jedis/Lettuce)兼容配置類
*/
@Configuration
public class RedisMultiModeConfig {
// ======================== 1. 連接池配置(按客戶端區(qū)分) ========================
/**
* Jedis連接池配置(client-type=jedis時(shí)生效)
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "jedis")
@ConfigurationProperties(prefix = "spring.redis.jedis.pool")
public JedisPoolConfig jedisPoolConfig() {
return new JedisPoolConfig();
}
/**
* Lettuce連接池配置(client-type=lettuce時(shí)生效)
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce")
@ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
public GenericObjectPoolConfig<?> lettucePoolConfig() {
return new GenericObjectPoolConfig<>();
}
// ======================== 2. 單機(jī)模式配置 ========================
@Configuration
@ConditionalOnProperty(name = "spring.redis.mode", havingValue = "standalone", matchIfMissing = true)
static class StandaloneSubConfig {
/**
* 單機(jī)模式基礎(chǔ)配置(IP、端口)
*/
@Bean
@ConfigurationProperties(prefix = "spring.redis.standalone")
public RedisStandaloneConfiguration standaloneConfig() {
return new RedisStandaloneConfiguration();
}
/**
* Jedis+單機(jī) 連接工廠
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "jedis")
public RedisConnectionFactory jedisStandaloneConnFactory(
RedisStandaloneConfiguration standaloneConfig, JedisPoolConfig poolConfig) {
JedisConnectionFactory factory = new JedisConnectionFactory(standaloneConfig);
factory.setPoolConfig(poolConfig); // 注入Jedis連接池
factory.setPassword(standaloneConfig.getPassword()); // 注入密碼(若有)
return factory;
}
/**
* Lettuce+單機(jī) 連接工廠
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce")
public RedisConnectionFactory lettuceStandaloneConnFactory(
RedisStandaloneConfiguration standaloneConfig, GenericObjectPoolConfig<?> poolConfig) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(standaloneConfig);
factory.setPoolConfig(poolConfig); // 注入Lettuce連接池
factory.setPassword(standaloneConfig.getPassword());
return factory;
}
}
// ======================== 3. 集群模式配置 ========================
@Configuration
@ConditionalOnProperty(name = "spring.redis.mode", havingValue = "cluster")
static class ClusterSubConfig {
/**
* 集群模式基礎(chǔ)配置(節(jié)點(diǎn)列表、重定向次數(shù))
*/
@Bean
@ConfigurationProperties(prefix = "spring.redis.cluster")
public RedisClusterConfiguration clusterConfig() {
return new RedisClusterConfiguration();
}
/**
* Jedis+集群 連接工廠
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "jedis")
public RedisConnectionFactory jedisClusterConnFactory(
RedisClusterConfiguration clusterConfig, JedisPoolConfig poolConfig) {
JedisConnectionFactory factory = new JedisConnectionFactory(clusterConfig);
factory.setPoolConfig(poolConfig);
factory.setPassword(clusterConfig.getPassword());
return factory;
}
/**
* Lettuce+集群 連接工廠
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce")
public RedisConnectionFactory lettuceClusterConnFactory(
RedisClusterConfiguration clusterConfig, GenericObjectPoolConfig<?> poolConfig) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(clusterConfig);
factory.setPoolConfig(poolConfig);
factory.setPassword(clusterConfig.getPassword());
return factory;
}
}
// ======================== 4. 哨兵模式配置 ========================
@Configuration
@ConditionalOnProperty(name = "spring.redis.mode", havingValue = "sentinel")
static class SentinelSubConfig {
/**
* 哨兵模式基礎(chǔ)配置(主節(jié)點(diǎn)名稱、哨兵節(jié)點(diǎn)列表)
*/
@Bean
@ConfigurationProperties(prefix = "spring.redis.sentinel")
public RedisSentinelConfiguration sentinelConfig() {
return new RedisSentinelConfiguration();
}
/**
* Jedis+哨兵 連接工廠
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "jedis")
public RedisConnectionFactory jedisSentinelConnFactory(
RedisSentinelConfiguration sentinelConfig, JedisPoolConfig poolConfig) {
JedisConnectionFactory factory = new JedisConnectionFactory(sentinelConfig);
factory.setPoolConfig(poolConfig);
factory.setPassword(sentinelConfig.getPassword());
return factory;
}
/**
* Lettuce+哨兵 連接工廠
*/
@Bean
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce")
public RedisConnectionFactory lettuceSentinelConnFactory(
RedisSentinelConfiguration sentinelConfig, GenericObjectPoolConfig<?> poolConfig) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(sentinelConfig);
factory.setPoolConfig(poolConfig);
factory.setPassword(sentinelConfig.getPassword());
return factory;
}
}
// ======================== 5. 通用RedisTemplate配置(所有模式共用) ========================
/**
* 自定義RedisTemplate,統(tǒng)一序列化方式(避免默認(rèn)JDK序列化的亂碼問(wèn)題)
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 1. Key序列化:String類型(直觀,便于Redis客戶端查看)
StringRedisSerializer keySerializer = new StringRedisSerializer();
template.setKeySerializer(keySerializer);
template.setHashKeySerializer(keySerializer);
// 2. Value序列化:JSON格式(支持對(duì)象存儲(chǔ),保留類型信息)
GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(valueSerializer);
template.setHashValueSerializer(valueSerializer);
// 3. 初始化模板
template.afterPropertiesSet();
return template;
}
}- 條件注解
@ConditionalOnProperty:通過(guò)name和havingValue指定生效條件,例如@ConditionalOnProperty(name = "spring.redis.mode", havingValue = "cluster")表示僅當(dāng)mode=cluster時(shí),該配置類才會(huì)被加載。 - 配置綁定
@ConfigurationProperties:自動(dòng)將application.yml中指定前綴的參數(shù)綁定到Bean的屬性中(如prefix = "spring.redis.jedis.pool"綁定到JedisPoolConfig),避免硬編碼。 - 統(tǒng)一接口
RedisConnectionFactory:無(wú)論哪種模式 / 客戶端,最終都返回RedisConnectionFactory,確保RedisTemplate無(wú)需修改即可適配。
業(yè)務(wù)代碼使用
/**
* Redis業(yè)務(wù)操作工具類(所有模式共用)
*/
@Service
public class RedisService {
// 注入配置類中自定義的RedisTemplate
@Resource
private RedisTemplate<String, Object> redisTemplate;
// ======================== 基礎(chǔ)操作示例 ========================
/**
* 存儲(chǔ)鍵值對(duì)(無(wú)過(guò)期時(shí)間)
*/
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 存儲(chǔ)鍵值對(duì)(帶過(guò)期時(shí)間)
*/
public void setWithExpire(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
/**
* 根據(jù)鍵獲取值
*/
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 根據(jù)鍵刪除值
*/
public Boolean delete(String key) {
return redisTemplate.delete(key);
}
// 更多操作(如Hash、List、Set等)可按需擴(kuò)展
}容器化部署動(dòng)態(tài)切換
若項(xiàng)目采用Docker/K8s部署,可通過(guò)環(huán)境變量動(dòng)態(tài)注入配置,無(wú)需修改配置文件:
# 示例:Docker啟動(dòng)時(shí)指定“Jedis+集群”模式
docker run -d \
-e SPRING_REDIS_CLIENT-TYPE=jedis \
-e SPRING_REDIS_MODE=cluster \
-e SPRING_REDIS_PASSWORD=your-pwd \
-e SPRING_REDIS_CLUSTER_NODES=134.188.194.30:20516,134.188.194.32:20516 \
your-app-image:latest




















