This is the 7th day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021
background
In the microservices concept, different services need to use different databases, including mysql and Redis, but this design conflicts with the high concurrency requirement because it is faster to query redis directly.
Integrate Redis multi-data source and lettuce connection pool
To integrate multiple redis data sources in SpringBoot, you need to mask the native RedisAutoConfiguration in the starter. And simulate RedisAutoConfiguration to set multiple beans of redisTemplate. It is injected through Autowired+Qualifier when used.
Depend on the add
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Copy the code
The configuration file
Configure multi-data source connection information in the YAML file, and configure a default Redis1 with port 6379 and Redis2 with port 6380
redis:
lettuce1:
host: localhost
password:
port: 6379
timeout: 5000
pool:
maxWaitMillis: 10000
minIdle: 5
maxIdle: 160
maxTotal: 500
lettuce2:
host: localhost
password:
port: 6380
timeout: 5000
pool:
maxWaitMillis: 10000
minIdle: 5
maxIdle: 160
maxTotal: 500
Copy the code
Eliminate RedisAutoConfiguration
Do not use the default SpringBoot for load initialization and must exclude RedisAutoConfiguration from annotations
@Import(value = { RedisLettuceConfig1.class, RedisLettuceConfig2.class })
@SpringBootApplication(exclude = { RedisAutoConfiguration.class })
Copy the code
Redis1 configuration class
Configure the database connection pool, data source, connection factory for data source, RedisTemplate. And set the serialization method
@EnableConfigurationProperties({RedisLettuceProperties1.class})
public class RedisLettuceConfig1 {
private static final String REDIS_STANDALONE_CONFIGURATION = "redisStandaloneConfiguration1";
private static final String LETTUCE_CLIENT_CONFIGURATION = "lettuceClientConfiguration1";
public static final String REDIS_CONNECTION_FACTORY = "redisLettuceConnectionFactory1";
public static final String REDIS_TEMPLATE = "redisLettuceTemplate1";
@Autowired
private RedisLettuceProperties1 redisProperties;
public RedisLettuceConfig1(a) {}@Bean( name = {"redisStandaloneConfiguration1"} )
public RedisStandaloneConfiguration redisStandaloneConfiguration(a) {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(this.redisProperties.getHost(), this.redisProperties.getPort());
if(! StringUtils.isEmpty(this.redisProperties.getPassword())) {
RedisPassword password = RedisPassword.of(this.redisProperties.getPassword());
configuration.setPassword(password);
}
configuration.setDatabase(this.redisProperties.getDbIndex());
return configuration;
}
@Bean( name = {"lettuceClientConfiguration1"} )
public LettuceClientConfiguration lettuceClientConfiguration(a) {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMinIdle(this.redisProperties.getPool().getMinIdle());
config.setMaxIdle(this.redisProperties.getPool().getMaxIdle());
config.setMaxTotal(this.redisProperties.getPool().getMaxTotal());
config.setMaxWaitMillis((long)this.redisProperties.getPool().getMaxWaitMillis());
config.setTestOnBorrow(this.redisProperties.getPool().getTestOnBorrow());
config.setTestOnReturn(this.redisProperties.getPool().getTestOnReturn());
LettucePoolingClientConfiguration configuration = LettucePoolingClientConfiguration.builder().poolConfig(config).commandTimeout(Duration.ofMillis((long)this.redisProperties.getTimeout())).build();
return configuration;
}
@Bean( name = {"redisLettuceConnectionFactory1"} )
public RedisConnectionFactory redisConnectionFactory(@Qualifier("redisStandaloneConfiguration1") RedisStandaloneConfiguration redisStandaloneConfiguration, @Qualifier("lettuceClientConfiguration1") LettuceClientConfiguration lettuceClientConfiguration) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
return factory;
}
@Bean( name = {"redisLettuceTemplate1"} )
public RedisTemplate<String, Object> redisTemplate(@Qualifier("redisLettuceConnectionFactory1") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
RedisSerializer<Object> objectSerializer = new JdkSerializationRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(objectSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(objectSerializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
returnredisTemplate; }}Copy the code
Redis2 configuration class
@EnableConfigurationProperties({RedisLettuceProperties2.class})
public class RedisLettuceConfig2 {
private static final String REDIS_STANDALONE_CONFIGURATION = "redisStandaloneConfiguration2";
private static final String LETTUCE_CLIENT_CONFIGURATION = "lettuceClientConfiguration2";
public static final String REDIS_CONNECTION_FACTORY = "redisLettuceConnectionFactory2";
public static final String REDIS_TEMPLATE = "redisLettuceTemplate2";
@Autowired
private RedisLettuceProperties2 RedisLettuceProperties;
public RedisLettuceConfig2(a) {}@Bean( name = {"redisStandaloneConfiguration2"} )
public RedisStandaloneConfiguration redisStandaloneConfiguration(a) {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(this.RedisLettuceProperties.getHost(), this.RedisLettuceProperties.getPort());
if(! StringUtils.isEmpty(this.RedisLettuceProperties.getPassword())) {
RedisPassword password = RedisPassword.of(this.RedisLettuceProperties.getPassword());
configuration.setPassword(password);
}
configuration.setDatabase(this.RedisLettuceProperties.getDbIndex());
return configuration;
}
@Bean( name = {"lettuceClientConfiguration2"} )
public LettuceClientConfiguration lettuceClientConfiguration(a) {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMinIdle(this.RedisLettuceProperties.getPool().getMinIdle());
config.setMaxIdle(this.RedisLettuceProperties.getPool().getMaxIdle());
config.setMaxTotal(this.RedisLettuceProperties.getPool().getMaxTotal());
config.setMaxWaitMillis((long)this.RedisLettuceProperties.getPool().getMaxWaitMillis());
config.setTestOnBorrow(this.RedisLettuceProperties.getPool().getTestOnBorrow());
config.setTestOnReturn(this.RedisLettuceProperties.getPool().getTestOnReturn());
LettucePoolingClientConfiguration configuration = LettucePoolingClientConfiguration.builder().poolConfig(config).commandTimeout(Duration.ofMillis((long)this.RedisLettuceProperties.getTimeout())).build();
return configuration;
}
@Bean( name = {"redisLettuceConnectionFactory2"} )
public RedisConnectionFactory redisConnectionFactory(@Qualifier("redisStandaloneConfiguration2") RedisStandaloneConfiguration redisStandaloneConfiguration, @Qualifier("lettuceClientConfiguration2") LettuceClientConfiguration lettuceClientConfiguration) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
return factory;
}
@Bean( name = {"redisLettuceTemplate2"} )
public RedisTemplate<String, Object> redisTemplate(@Qualifier("redisLettuceConnectionFactory2") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
RedisSerializer<Object> objectSerializer = new JdkSerializationRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(objectSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(objectSerializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
returnredisTemplate; }}Copy the code
test
Reference the redisTemplate and specify which bean it came from
@Autowired
@Qualifier(RedisLettuceConfig1.REDIS_TEMPLATE)
private RedisTemplate redisTemplate;
HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
String value = hashOperations.get("users", userId);
Copy the code
summary
Springboot is a simple process to configure redis multi-data sources, importing dependencies, adding configurations, and initializing beans. Note that Redis has a default implementation class, so use the @qualifier annotation and specify the name of the previous Bean injection. Otherwise, the default configuration will be used after automatic injection and the specified Redis data source will not be used.