微服务配置Redis多数据源

1,278 阅读2分钟

这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

背景

在微服务概念中,不同的服务需要使用不同的数据库,包括mysqlredis,但是如果是需要高并发又与这样设计造成冲突,因为直接查询redis会更快一些。

集成Redis多数据源与lettuce连接池

springboot中集成redis多个数据源需要屏蔽starter中带有的原生RedisAutoConfiguration。 并模拟RedisAutoConfiguration,设置多个redisTemplate的bean。并在使用时通过Autowired+Qualifier注入。

依赖添加

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置文件

yaml文件中配置多数据源连接信息,配置一个端口为6379的默认Redis1和一个端口为6380的Redis2

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	  

排除RedisAutoConfiguration

不使用默认的springboot进行加载初始化,必须要在注解中排除RedisAutoConfiguration

@Import(value = {
        RedisLettuceConfig1.class,
        RedisLettuceConfig2.class
})

@SpringBootApplication(exclude = {
        RedisAutoConfiguration.class
})

Redis1配置类

配置lettuce连接池、数据源、数据源的连接工厂、RedisTemplate。并设置序列化方式

@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() {
    }

    @Bean(
        name = {"redisStandaloneConfiguration1"}
    )
    public RedisStandaloneConfiguration redisStandaloneConfiguration() {
        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() {
        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);
        return redisTemplate;
    }

}

Redis2配置类

@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() {
    }

    @Bean(
        name = {"redisStandaloneConfiguration2"}
    )
    public RedisStandaloneConfiguration redisStandaloneConfiguration() {
        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() {
        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);
        return redisTemplate;
    }

}

测试

引用redisTemplate并指定来自哪个bean

    @Autowired
    @Qualifier(RedisLettuceConfig1.REDIS_TEMPLATE)
    private RedisTemplate redisTemplate;
	
    HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
    String value = hashOperations.get("users", userId);

小结

springboot配置redis多数据源的过程比较简单,引入依赖包,添加配置,初始化Bean。 需要注意的是Redis有默认的实现类了,所以在装配使用的时候,要加上@Qualifier注解并指定前面Bean注入的名字,不然自动注入后会使用默认的配置,不能使用指定的Redis数据源。