Spring boot multi data source redis configuration

Time:2020-2-13

Summary

Based on spring boot 2.0.7, this paper explains how to configure redis with multiple data sources. Lettuce is used as the redis client, and an example code is attached.

Redis configuration

configuration file

skyarthur:
  redis1:
    host: 127.0.0.1
    port: 6378
    lettuce:
      pool:
        min-idle: 5
        max-idle: 10
        max-active: 8
        max-wait: 1ms
      shutdown-timeout: 100ms
  redis2:
    host: 127.0.0.1
    port: 6379
    lettuce:
      pool:
        min-idle: 5
        max-idle: 10
        max-active: 8
        max-wait: 1ms
      shutdown-timeout: 100ms

Two redis data sources are configured and lettuce pool is used as the redis client

Configuration class

package com.skyarthur.springboot.config;

import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
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.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
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.StringRedisTemplate;

/**
 * Created by skyarthur on 2019-12-21
 */

@Configuration
@ConfigurationProperties(prefix = "skyarthur")
@Getter
@Setter
public class RedisConfig {

    private RedisProperties redis1;
    private RedisProperties redis2;

    @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean(ClientResources.class)
    public DefaultClientResources lettuceClientResources() {
        return DefaultClientResources.create();
    }

    @Bean(name = "stringRedisTemplate1")
    @Primary
    public StringRedisTemplate stringRedisTemplate1(
            @Qualifier("Redis1LettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean(name = "Redis1LettuceConnectionFactory")
    @Primary
    public LettuceConnectionFactory Redis1LettuceConnectionFactory(ClientResources clientResources) {
        RedisStandaloneConfiguration redis1StandaloneConfiguration = getStandaloneConfig(redis1);
        LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, redis1);
        return new LettuceConnectionFactory(redis1StandaloneConfiguration, clientConfig);
    }

    @Bean(name = "stringRedisTemplate2")
    public StringRedisTemplate stringRedisTemplate2(
            @Qualifier("Redis2LettuceConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean(name = "Redis2LettuceConnectionFactory")
    public LettuceConnectionFactory Redis2LettuceConnectionFactory(ClientResources clientResources) {
        RedisStandaloneConfiguration redis1StandaloneConfiguration = getStandaloneConfig(redis2);
        LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, redis2);
        return new LettuceConnectionFactory(redis1StandaloneConfiguration, clientConfig);
    }


    /**
     * redis standalone config
     *
     *@ param redisproperties redis configuration parameters
     * @return RedisStandaloneConfiguration
     */
    private RedisStandaloneConfiguration getStandaloneConfig(RedisProperties redisProperties) {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(redisProperties.getHost());
        config.setPort(redisProperties.getPort());
        config.setPassword(RedisPassword.of(redisProperties.getPassword()));
        config.setDatabase(redisProperties.getDatabase());
        return config;
    }

    /**
     *Build lettucleclientconfiguration
     *
     * @param clientResources clientResources
     * @param redisProperties redisProperties
     * @return LettuceClientConfiguration
     */
    private LettuceClientConfiguration getLettuceClientConfiguration(ClientResources clientResources,
                                                                     RedisProperties redisProperties) {
        LettuceClientConfiguration.LettuceClientConfigurationBuilder builder =
                createBuilder(redisProperties.getLettuce().getPool());
        if (redisProperties.isSsl()) {
            builder.useSsl();
        }
        if (redisProperties.getTimeout() != null) {
            builder.commandTimeout(redisProperties.getTimeout());
        }
        if (redisProperties.getLettuce() != null) {
            RedisProperties.Lettuce lettuce = redisProperties.getLettuce();
            if (lettuce.getShutdownTimeout() != null
                    && !lettuce.getShutdownTimeout().isZero()) {
                builder.shutdownTimeout(
                        redisProperties.getLettuce().getShutdownTimeout());
            }
        }
        builder.clientResources(clientResources);
        return builder.build();
    }

    /**
     *Create lettucleclientconfigurationbuilder
     *
     *@ param pool connection pool configuration
     * @return LettuceClientConfigurationBuilder
     */
    private LettuceClientConfiguration.LettuceClientConfigurationBuilder createBuilder(RedisProperties.Pool pool) {
        if (pool == null) {
            return LettuceClientConfiguration.builder();
        }
        return LettucePoolingClientConfiguration.builder()
                .poolConfig(getPoolConfig(pool));
    }

    /**
     * pool config
     *
     *@ param properties redis parameter configuration
     * @return GenericObjectPoolConfig
     */
    private GenericObjectPoolConfig getPoolConfig(RedisProperties.Pool properties) {
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxTotal(properties.getMaxActive());
        config.setMaxIdle(properties.getMaxIdle());
        config.setMinIdle(properties.getMinIdle());
        if (properties.getMaxWait() != null) {
            config.setMaxWaitMillis(properties.getMaxWait().toMillis());
        }
        return config;
    }
}

Refer to the official spring configuration for the above configurationRedisAutoConfiguration, LettuceConnectionConfiguration。 In short:RedisAutoConfigurationRegistered 2 beans,RedisTemplateandStringRedisTemplateThese two beans depend onRedisConnectionFactoryInjection of atRedisAutoConfigurationAs you can see,RedisConnectionFactoryThere are two implementations,LettuceConnectionFactoryandJedisConnectionFactoryFor details, please refer to the official configurationLettuceConnectionConfiguration

Single measurement

package com.skyarthur.springboot.config;

import com.skyarthur.springboot.ApplicationTests;
import com.skyarthur.springboot.common.enums.RedisType;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * Created by skyarthur on 2019-12-21
 */

public class RedisConfigTest extends ApplicationTests {

    @Autowired
    @Qualifier("stringRedisTemplate1")
    private StringRedisTemplate stringRedisTemplate1;

    @Autowired
    @Qualifier("stringRedisTemplate2")
    private StringRedisTemplate stringRedisTemplate2;

    @Test
    public void test() {
        LettuceConnectionFactory factory = (LettuceConnectionFactory) stringRedisTemplate1.getConnectionFactory();
        Assert.assertNotNull(factory);
        Assert.assertEquals(6378, factory.getPort());
        Assert.assertEquals("127.0.0.1", factory.getHostName());
        factory = (LettuceConnectionFactory) stringRedisTemplate2.getConnectionFactory();
        Assert.assertNotNull(factory);
        Assert.assertEquals(6379, factory.getPort());
        Assert.assertEquals("127.0.0.1", factory.getHostName());

        stringRedisTemplate1.opsForValue().set(RedisType.PERSON_INFO.getRealKey("test"), "6378");
        stringRedisTemplate2.opsForValue().set("test", "6379");

        Assert.assertEquals("6378", stringRedisTemplate1.opsForValue().get(RedisType.PERSON_INFO.getRealKey("test")));
        Assert.assertEquals("6379", stringRedisTemplate2.opsForValue().get("test"));
    }
}

Sample code

  • Code example
  • Multi data source redis configuration commit

Reference document

  • https://juejin.im/post/5ba0a0…
  • https://fastdep.louislivi.com…
  • https://www.jianshu.com/p/5b0…

Recommended Today

Understanding cookie, session, token, JWT

History of development 1. A long time ago,WebBasically, it’s just browsing documents. Since it’s browsing, as a server, it doesn’t need to record who browsed what documents in a certain period of time. Each request is a new oneHTTPProtocol is request plus response, especially I don’t have to remember who just sent itHTTPRequests, every request […]