如何在一个项目中配置多个RedisTemplate

在一个项目中配置多个 RedisTemplate 是常见需求,例如连接不同的 Redis 服务器、不同的数据库,或为不同业务定制不同的序列化方式。Spring Data Redis 提供了灵活的配置方式,允许我们定义多个 RedisConnectionFactory 和对应的 RedisTemplate Bean,并通过 @Qualifier 在注入时区分。

下面给出一个完整的配置方案,包括基于 YAML 的多数据源定义和 Java 配置类的实现。


1. 依赖准备

确保已引入 Spring Data Redis 和连接池依赖(以 Lettuce 为例):

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

2. YAML 中定义多个 Redis 连接信息

application.yml 中可以为不同的 Redis 数据源分别配置连接参数,使用自定义前缀:

spring:
  # 默认数据源(可选,也可以不用)
  redis:
    host: localhost
    port: 6379
    database: 0
    lettuce:
      pool:
        max-active: 8

# 自定义数据源1
redis1:
  host: redis1.example.com
  port: 6379
  password: pass1
  database: 1
  lettuce:
    pool:
      max-active: 16
      max-idle: 8
      min-idle: 2

# 自定义数据源2
redis2:
  host: redis2.example.com
  port: 6380
  password: pass2
  database: 2
  lettuce:
    pool:
      max-active: 16
      max-idle: 8
      min-idle: 2

3. Java 配置类:创建多个 RedisConnectionFactory 和 RedisTemplate

创建一个配置类 MultipleRedisConfig,通过 @ConfigurationProperties 读取自定义前缀的配置,并为每个数据源创建独立的 LettuceConnectionFactoryRedisTemplate

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
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.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.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;

@Configuration
public class MultipleRedisConfig {

    // ---------- 第一个数据源 ----------
    @Bean
    @ConfigurationProperties(prefix = "redis1")   // 绑定 YAML 中以 redis1 开头的属性
    public RedisProperties redis1Properties() {
        return new RedisProperties();   // 复用 Spring Boot 的 RedisProperties 类
    }

    @Bean
    public LettuceConnectionFactory redis1ConnectionFactory() {
        RedisProperties props = redis1Properties();
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(props.getHost());
        config.setPort(props.getPort());
        config.setPassword(props.getPassword());
        config.setDatabase(props.getDatabase());

        // 连接池配置
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(props.getLettuce().getPool().getMaxActive());
        poolConfig.setMaxIdle(props.getLettuce().getPool().getMaxIdle());
        poolConfig.setMinIdle(props.getLettuce().getPool().getMinIdle());
        poolConfig.setMaxWait(Duration.ofMillis(props.getLettuce().getPool().getMaxWait().toMillis()));

        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .poolConfig(poolConfig)
                .build();

        return new LettuceConnectionFactory(config, clientConfig);
    }

    @Bean
    public RedisTemplate<String, Object> redis1Template() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redis1ConnectionFactory());
        // 设置序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    // ---------- 第二个数据源 ----------
    @Bean
    @ConfigurationProperties(prefix = "redis2")
    public RedisProperties redis2Properties() {
        return new RedisProperties();
    }

    @Bean
    public LettuceConnectionFactory redis2ConnectionFactory() {
        // 与第一个类似,从 redis2Properties() 读取配置
        RedisProperties props = redis2Properties();
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(props.getHost());
        config.setPort(props.getPort());
        config.setPassword(props.getPassword());
        config.setDatabase(props.getDatabase());

        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(props.getLettuce().getPool().getMaxActive());
        poolConfig.setMaxIdle(props.getLettuce().getPool().getMaxIdle());
        poolConfig.setMinIdle(props.getLettuce().getPool().getMinIdle());
        poolConfig.setMaxWait(Duration.ofMillis(props.getLettuce().getPool().getMaxWait().toMillis()));

        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .poolConfig(poolConfig)
                .build();

        return new LettuceConnectionFactory(config, clientConfig);
    }

    @Bean
    public RedisTemplate<String, Object> redis2Template() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redis2ConnectionFactory());
        // 可以设置不同的序列化方式,这里与第一个相同
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    // 如果还需要默认的 RedisTemplate(基于 spring.redis 配置),可以另外配置
    // 注意:需要处理主数据源的 @Primary
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.redis")
    public RedisProperties defaultRedisProperties() {
        return new RedisProperties();
    }

    @Bean
    @Primary
    public LettuceConnectionFactory defaultRedisConnectionFactory() {
        // 类似构造,使用 defaultRedisProperties()
        // ...
        return factory;
    }

    @Bean
    @Primary
    public RedisTemplate<String, Object> defaultRedisTemplate() {
        // ...
        return template;
    }
}

注意RedisProperties 是 Spring Boot 内置的配置类,可以直接使用。上面的代码中通过 @ConfigurationProperties 绑定自定义前缀,完美复用现有属性类。


4. 使用多个 RedisTemplate

在 Service 中通过 @Qualifier 指定要注入的 Bean:

@Service
public class MyService {
    @Autowired
    @Qualifier("redis1Template")
    private RedisTemplate<String, Object> redis1Template;

    @Autowired
    @Qualifier("redis2Template")
    private RedisTemplate<String, Object> redis2Template;

    public void demo() {
        redis1Template.opsForValue().set("key1", "value from redis1");
        redis2Template.opsForValue().set("key2", "value from redis2");
    }
}

5. 扩展:支持 Redis 集群或哨兵

如果某个数据源是集群模式,可以将 RedisStandaloneConfiguration 替换为 RedisClusterConfigurationRedisSentinelConfiguration,并使用对应的构造方法。例如:

RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration()
    .clusterNode("host1", 6379)
    .clusterNode("host2", 6379);

然后在创建 LettuceConnectionFactory 时传入该配置。


6. 注意事项

  • 连接池:每个 LettuceConnectionFactory 拥有独立的连接池,配置时注意内存和资源开销。
  • 事务:如果需要支持 Redis 事务,需在 RedisTemplate 上设置 setEnableTransactionSupport(true)
  • 序列化:根据业务需求选择合适的序列化方式(如 Jackson、JdkSerializationRedisSerializer、StringRedisSerializer 等)。注意跨语言兼容性和性能。
  • 默认 Bean:如果只配置了多个 RedisTemplate,而没有 @Primary 标记,Spring 会因类型冲突而报错。要么指定一个 @Primary,要么在注入时始终使用 @Qualifier 明确指定。
  • 配置文件结构:上述代码假设我们的 YAML 结构与 RedisProperties 一致。如果自定义字段,可以创建自己的配置类。

通过以上方案,我们可以灵活地在一个项目中管理多个 Redis 数据源,满足各种业务隔离或异构需求。