开发者

Spring工程中集成多个redis数据源的思路详解

目录
  • 问题
  • 思路
  • 解决
    • FhRedisConfig.Java
    • RedisConfig.java
    • Controller.java
  • 总结
    • 参考

      问题

      有个项目需要在同一个Spring工程中集成2个redis数据源。

      思路

      配置2个redis连接工厂,再配置2个redistemplate。然后,在使用缓存的时候,分别注入不同的redistemplate解决这个问题。这里主要是使用了spring中的2个注释:

      • @Primary:设置默认bean
      • @Qualifier:指定注入bean

      解决

      FhRedisConfig.java

      这个类是配置第2个多余的redis,对application.yml文件中自定义redis配置映射类。如果application.yml文件中有如下配置:

      fh:
      	redis:
      		host: 12.86.12.9
      		password: swdghop
      		port: 6379
      		database:7

      这对应配置类如下:

      package com.xxxx.framework.config;
      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      /**
       * redis配置类
       */
      @Data
      @ConfigurationProperties(prefix = "fh.redis")
      public class FhRedisConfig {
          /**
           * 主机地址
           */
          private String host;
          /**
           * 密码
           */
          private String password;
          /**
           * Redis 服务器端口号
           * 默认值:6379(Redis 默认端口)
           */
          private int port = 6381;
          /**
           * Redis 数据库索引(0-15)
           * 默认值:0
           */
          private int database = 0;
      }

      RedisConfig.java

      这是redis配置类,这里主要配置2个redis连接工厂,2个redistemplate的bean。而且,使用@Primary设置redistemplate类注入的默认bean为哪个redistemplate的bean。而且,如果增加了对redis集群配置的支持。

      package com.xxxx.framework.config;
      import io.lettuce.core.cluster.ClusterClientOptions;
      import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
      import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
      import org.springframework.boot.context.properties.EnableConfigurationProperties;
      import org.springframework.cache.annotation.CachingConfigurerSupport;
      import org.springframework.cache.annotation.EnableCaching;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Primary;
      import org.springframework.data.redis.connection.RedisClusterConfiguration;
      import org.springframework.data.redis.connection.RedisConnectionFactory;
      import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
      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.core.script.DefaultRedisScript;
      import org.springframework.data.redis.serializer.StringRedisSerializer;
      import org.springframework.util.CollectionUtils;
      import javax.annotation.Resource;
      import java.util.List;
      /**
       * redis配置
       * 
       */
      @Configuration
      @EnableCaching
      @EnableConfigurationProperties(FhRedisConfig.class)
      public class RedisConfig extends CachingConfigurerSupport
      {
          @Resource
          private FhRedisConfig fhRedisConfig;
          @Value("${spring.profiles.active:default}")
          private String activeProfile;
          /**
           * 默认redis连接池
           * @return 默认redis连接池
           */
          @Bean
          @Primary
          public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {
              // 从 RedisProperties 提取连接池配置(如果存在)
              return getRedisConnectionFactory(redisProperties, redisProperties.getHost(), redisProperties.getPort(), redisProperties.getPassword(),
                      redisProperties.getDatabase(), redisProperties.getCluster() == null ? null : redisProperties.getCluster().getNodes());
          }
          /**
           * redis连接池
           * @return redis连接池
           */
          @Bean
          public RedisConnectionFactory fhRedisConnectionFactory(RedisProperties redisProperties) {
              return getRedisConnectionFactory(redisProperties, fhRedisConfig.getHost(), fhRedisConfig.getPort(), fhRedisConfig.getPassword(),
                      fhRedisConfig.getDatabase(), null);
          }
          /**
           * redis客户端
           * @param connectionFactory redis连接池
           * @return redis客户端
           */
          @Bean
          public RedisTemplate<Object, Object> fhRedisTemplate(@Qualifier("fhRedisConnectionFactory")RedisConnectionFactory connectionFactory)
          {
              return getRedisTemplate(connectionFactory);
          }
          /**
           * 默认redis客户端
           * @param connectionFactory 默认redis连接池
           * @return 默认redis客户端
           */
          @Bean
          @Primary
          public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
          {
              return getRedisTemplate(connectionFactory);
          }
          private static RedisTemplate<Object, Object> getRedisTemplate(RedisConnectionFactory connectionFactory) {
              RedisTemplate<Object, Object> template = new RedisTemplate<>();
              template.setConnectionFactory(connectionFactory);
              Fastjson2JsonRedisSerializer<Object> serializer = new FastJson2JsonRedisSerializer<>(Object.class);
              // 使用StringRedisSerializer来序列化和反序列化redis的key值
              template.setKeySerializer(new StringRedisSerializer());
              template.setValueSerializer(serializer);
              // Hash的key也采用StringRedisSerializer的序列化方式
              template.setHashKeySerializer(new StringRedisSerializer());
              template.setHashValueSerializer(serializer);
              template.afterPropertiesSet();
              return template;
          }
          private RedisConnectionFactory getRedisConnectionFactory(RedisProperties redisProperties, String host, int port, String password, int database, List<String> nodes) {
              LettuceConnectionFactory lettuceConnectionFactory;
              // 根据是否是集群模式选择不同的配置
              javascriptif (!CollectionUtils.isEmpty(nodes)) {
                  // 配置集群拓扑刷新选项
                  ClusterTopologyRefreshOptions refreshOptions = ClusterTopologyRefreshOptions.builder()
                          .refreshPeriod(redisProperties.getLettuce().getCluster().getRefresh().getPeriod())
                          .enableAdaptiveRefreshTrigger(
                                  ClusterTopologyRefreshOptions.RefreshTrigger.MOVED_REDIRECT,
                                  ClusterTopologyRefreshOptions.RefreshTrigger.PERSISTENT_RECONNECTS)
                          .build();
                  ClusterClientOptions clientOptions = ClusterClientOptions.builder()
                          .topologyRefreshOptions(refreshOptions)
                          .build();
                  GenericObjectPoolConfig<?> poolConfig = getGenericObjectPoolConfig(redisProperties);
                  LettucePoolingClientConfiguration.LettucePoolingSslClientConfigurationBuilder lettucePoolingSslClientConfigurationBuilder = LettucePoolingClientConfiguration.builder()
                          .clientOptions(clientOptions)
                          .poolConfig(poolConfig)  // 关键:设置连接池
                          .commandTimeout(redisProperties.getTimeout())
                          .useSsl();
                  if (!activeProfile.equals("prod")) {
                      lettucePoolingSslClientConfigurationBuilder.disablePeerVerification();
                  }
                  LettucePoolingClientConfiguration poolingClientConfig = lettucePoolingSslClientConfigurationBuilder.build();
                  // 创建集群配置
                  RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(nodes);
                 http://www.devze.com clusterConfig.setPassword(password);
                  // 创建 LettuceConnectionFactory
                  lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfig, poolingClientConfig);
              } else {
                  // 非集群模式保持原逻辑
                  GenericObjectPoolConfig<?> poolConfig = getGenericObjectPoolConfig(redisProperties);
                  LettucePoolingClientConfiguration.LettucePoolingSslClientConfigurationBuilder lettucePoolingSslClientConfigurationBuilder = LettucePoolingClientConfiguration.builder()
                          .poolConfig(poolConfig)  // 关键:设置连接池
                          .commandTimeout(redisProperties.getTimeout())
                          .useSsl();
                  if (!activeProfile.equals("prod")) {
                      lettucePoolingSslClientConfigurationBuilder.disablePeerVerification();
                  }
                  RedisStaticMasterReplicaConfiguration serverConfig = new RedisStaticMasterReplicaConfiguration(host, port);
                  serverConfig.setPassword(password);
              编程客栈    LettucePoolingClientConfiguration poolingClientConfig = lettucePoolingSslClientConfigurationBuilder.build();
                  lettuceConnectionFactory = new LettuceConnectionFactory(serverConfig, poolingClientConfig);
              }
              lettuceConnectionFactory.setDatabase(database);
              return lettuceConnectionFactory;
          }
          private static GenericObjectPoolConfig<?> getGenericObjectPoolConfig(RedisProperties redisPropertiewww.devze.coms) {
              GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
              if (redisProperties.getLettuce().getPool() != null) {
                  RedisProperties.Pool poolProps = redisProperties.getLettuce().getPool();
                  poolConfig.setMaxTotal(poolProps.getMaxActive());      // max-active
                  poolConfig.setMaxIdle(poolProps.getMaxIdle());        // max-idle
                  poolConfig.setMinIdle(poolProps.getMinIdle());        // min-idle
                  poolConfig.setMaxWaitMillis(poolProps.getMaxWait().toMillis());        // max-wait
              }
              return poolConfig;
          }
      }

      注意@Qualifier注释的使用,这里使用指定了特定的redis连接工厂。下面的在业务代码中注入redistemaplte的时候,也需要使用呢@Qualifier注释来使用特定的redis集群。

      Controller.java

      这是业务代码中,注入使用特定的redis集群,如下代码:

      @Resource
      @Qualifier("fhRedphpisTemplate")
      private RedisTemplate<String, Integer> fhRedisTemplate;

      如果不需要使用特定redis,只需要使用默认redis则不需要@Qualifier注释,如下:

      @Resource
      public RedisTemplate redisTemplate;

      总结

      这就是Spring项目redis多数据源问题。主要就是通过@Primary注释来配置默认bean,通过@Qualifier注释来指定使用的bean。

      参考

      • Multiple Redis Connections in Spring Boot
      • Spring Boot Redis CRUD Example
      • The Spring @Qualifier Annotation
      • Connection Modes
      • 【Redis】Integration with Spring Boot
      • Accessing AWS ElastiCache (Redis) from different Amazon VPC(s) via AWS PrivateLink

      到此这篇关于Spring工程中集成多个redis数据源的思路详解的文章就介绍到这了,更多相关Spring多个redis数据源内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜