參考資料
前人栽樹, 后人乘涼 😊
SpringBoot2.X整合Redis(單機+集群+多數據源)-Lettuce版_lonely_bin的博客-CSDN博客
前提條件
- 兩個數據源, 且兩個數據源都是以集群方式部署的
- Lettuce 接入
- 本次測試的數據源
- 數據源1: 192.168.10.1:6380
- 數據源2: 192.168.10.1:6381
pom依賴文件
<!--pom.xml-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--測試依賴包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!--redis連接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
</dependencies>
配置文件
// application.yml
spring:
redis:
password: your'spassword # 密碼(默認為空)
timeout: 6000 # 連接超時時長(毫秒)
cluster:
nodes: 192.168.10.1:6380
max-redirects: 3 # 獲取失敗 最大重定向次數
lettuce:
pool:
max-active: 1000 # 連接池最大連接數(使用負值表示沒有限制)
max-wait: -1ms # 連接池最大阻塞等待時間(使用負值表示沒有限制)
max-idle: 10 # 連接池中的最大空閑連接
min-idle: 5 # 連接池中的最小空閑連接
secondaryRedis:
cluster:
nodes: 192.168.10.1:6381
password: your'spassword
多集群配置文件
// RedisConfig.java
package top.sunchangheng.multiredis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.HashMap;
import java.util.Map;
/*** 功能描述: 多集群數據源配置
*/
@Configuration
public class RedisConfig {
@Autowired
private Environment environment;
/**
* 配置lettuce連接池
*/
@Bean
@Primary
@ConfigurationProperties (prefix = "spring.redis.cluster.lettuce.pool")
public GenericObjectPoolConfig redisPool() {
return new GenericObjectPoolConfig();
}
/**
* 配置第一個數據源的
*/
@Bean ("redisClusterConfig")
@Primary
public RedisClusterConfiguration redisClusterConfig() {
Map<String, Object> source = new HashMap<>(8);
source.put("spring.redis.cluster.nodes", environment.getProperty("spring.redis.cluster.nodes"));
RedisClusterConfiguration redisClusterConfiguration;
redisClusterConfiguration = new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration",
source));
redisClusterConfiguration.setPassword(environment.getProperty("spring.redis.password"));
return redisClusterConfiguration;
}
/**
* 配置第一個數據源的連接工廠
* 這里注意:需要添加@Primary 指定bean的名稱,目的是為了創建兩個不同名稱的LettuceConnectionFactory
*/
@Bean ("lettuceConnectionFactory")
@Primary
public LettuceConnectionFactory lettuceConnectionFactory(GenericObjectPoolConfig redisPool, @Qualifier (
"redisClusterConfig") RedisClusterConfiguration redisClusterConfig) {
LettuceClientConfiguration clientConfiguration =
LettucePoolingClientConfiguration.builder().poolConfig(redisPool).build();
return new LettuceConnectionFactory(redisClusterConfig, clientConfiguration);
}
/**
* 配置第一個數據源的RedisTemplate
* 注意:這里指定使用名稱=factory 的 RedisConnectionFactory
* 並且標識第一個數據源是默認數據源 @Primary
*/
@Bean ("redisTemplate")
@Primary
public RedisTemplate redisTemplate(@Qualifier ("lettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
return getRedisTemplate(redisConnectionFactory);
}
/**
* 配置第二個數據源
*/
@Bean ("secondaryRedisClusterConfig")
public RedisClusterConfiguration secondaryRedisConfig() {
Map<String, Object> source = new HashMap<>(8);
source.put("spring.redis.cluster.nodes", environment.getProperty("spring.secondaryRedis.cluster.nodes"));
RedisClusterConfiguration redisClusterConfiguration;
redisClusterConfiguration = new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration",
source));
redisClusterConfiguration.setPassword(environment.getProperty("spring.redis.password"));
return redisClusterConfiguration;
}
@Bean ("secondaryLettuceConnectionFactory")
public LettuceConnectionFactory secondaryLettuceConnectionFactory(GenericObjectPoolConfig redisPool, @Qualifier (
"secondaryRedisClusterConfig") RedisClusterConfiguration secondaryRedisClusterConfig) {
LettuceClientConfiguration clientConfiguration =
LettucePoolingClientConfiguration.builder().poolConfig(redisPool).build();
return new LettuceConnectionFactory(secondaryRedisClusterConfig, clientConfiguration);
}
/**
* 配置第一個數據源的RedisTemplate
* 注意:這里指定使用名稱=factory2 的 RedisConnectionFactory
*/
@Bean ("secondaryRedisTemplate")
public RedisTemplate secondaryRedisTemplate(@Qualifier ("secondaryLettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
return getRedisTemplate(redisConnectionFactory);
}
/*** 功能描述: 根據連接工廠獲取一個RedisTemplate
*/
private RedisTemplate getRedisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
到這里, 已經配置好了多集群數據源了, 但是需要注意的是: 注入redisTempalte
時, 需要根據名稱進行依賴注入, 如下圖中的測試案例
測試
// RedisTest.java
package top.sunchangheng.multiredis;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith (SpringRunner.class)
public class RedisTest {
@Autowired
RedisTemplate<String, Object> redisTemplate;
@Autowired
@Qualifier ("secondaryRedisTemplate")
RedisTemplate<String, Object> secondaryRedisTemplate;
@Autowired
private Environment environment;
@Test
public void testEnvironment() {
System.out.println("開始測試");
String property = environment.getProperty("spring.secondaryRedis.cluster.nodes");
System.out.println("property = " + property);
System.out.println("over");
}
// 同時設置兩個數據源的數據
@Test
public void testTemplateSet() {
System.out.println("同時設置數據");
redisTemplate.opsForValue().set("redis-key2", "redisTemplate");
secondaryRedisTemplate.opsForValue().set("redis-key2", "secondaryRedisTemplate");
System.out.println("over");
}
// 同時獲取兩個數據源的數據
@Test
public void testTemplateGet() {
System.out.println("同時獲取數據");
Object key1 = redisTemplate.opsForValue().get("redis-key2");
Object key2 = secondaryRedisTemplate.opsForValue().get("redis-key2");
System.out.println("key1 = " + key1);
System.out.println("key2 = " + key2);
System.out.println("over");
}
}