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.