spring boot整合redis多实例

Posted wenwblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring boot整合redis多实例相关的知识,希望对你有一定的参考价值。

最近项目中遇到需要连接两个redis实例的情况,于是就在spring boot原先的基础上修改了一点。

1. 定义配置文件的bean,继承自RedisProperties

  • 下面是配置文件的内容
redis:
  config:
    multiple:
    - name: develop
      database: 0
      lettuce:
        pool:
          max-idle: 10
          max-active: 1000
          max-wait: 1000ms
          min-idle: 5
      timeout: 100000ms
      cluster:
        nodes: 192.168.2.86:6380,192.168.2.87:6380,192.168.2.88:6380
    - name: test
      database: 0
      lettuce:
        pool:
          max-idle: 10
          max-active: 1000
          max-wait: 1000ms
          min-idle: 5
      timeout: 100000ms
      cluster:
        nodes: 192.168.2.86:6379,192.168.2.87:6379,192.168.2.88:6379
  • 配置文件对应的实体
@Data
public class MultipleRedisProperties extends RedisProperties {

    /**
     * redis的自定义名称
     */
    private String name;

}

2. 获取配置文件属性的值

@Getter
@Setter
@ConfigurationProperties(prefix = "redis.config")
public class RedisConfigPropertySupport {


    List<MultipleRedisProperties> multiple = new ArrayList<>();


}

3.加载到spring 容器中

@Getter
@Setter
@Configuration
@EnableConfigurationProperties(RedisConfigPropertySupport.class)
public class RedisPropertiesAutoConfig {

    private RedisConfigPropertySupport redisProperties;

    public RedisPropertiesAutoConfig(RedisConfigPropertySupport redisProperties) {
        this.redisProperties = redisProperties;
    }
}
  • 创建redis部署模式的枚举值
public enum RedisModeEnum {

    /**
     * 单机
     */
    STAND_ALONE,

    /**
     * 哨兵
     */
    SENTINEL,

    /**
     * 集群
     */
    CLUSTER

}

4. 使用spring boot的创建连接工厂进行配置redis的连接工厂类

public abstract class AbstractRedisConnectionFactoryConfig implements BeanFactoryAware, InitializingBean {

    @Autowired
    private RedisPropertiesAutoConfig redisProperties;

    private BeanFactory beanFactory;

    private static final String DEFAULT = "default";


    @Override
    public void afterPropertiesSet() {
        ConfigurableListableBeanFactory listableBeanFactory = (ConfigurableListableBeanFactory) this.getBeanFactory();
        if (getRedisProperties().getRedisProperties() == null || CollectionUtils.isEmpty(getRedisProperties().getRedisProperties().getMultiple())) {
            RedisConnectionFactory defaultConnectionFactory = buildRedisConnectionFactory(null);
            listableBeanFactory.registerSingleton(DEFAULT + "_redisConnectionFactory", defaultConnectionFactory);
        }
        getRedisProperties().getRedisProperties().getMultiple().forEach(redisProperty -> {
            RedisConnectionFactory redisConnectionFactory = buildRedisConnectionFactory(redisProperty);
            listableBeanFactory.registerSingleton(redisProperty.getName().trim() + "_redisConnectionFactory", redisConnectionFactory);
        });
    }

    /**
     * 创建{@link RedisConnectionFactory},由子类实现
     *
     * @param redisProperties
     * @return
     */
    protected abstract RedisConnectionFactory buildRedisConnectionFactory(RedisProperties redisProperties);

    /**
     * 根据redisProperty判断redis部署模式
     *
     * @param redisProperty redisProperty
     * @return {@link RedisModeEnum}
     */
    protected abstract RedisModeEnum getRedisMode(RedisProperties redisProperty);


    static class RedisConnectionPoolBuilderFactory {

        public LettuceClientConfiguration.LettuceClientConfigurationBuilder createBuilder(RedisProperties.Pool properties) {
            return LettucePoolingClientConfiguration.builder().poolConfig(getPoolConfig(properties));
        }

        private GenericObjectPoolConfig<?> getPoolConfig(RedisProperties.Pool properties) {
            GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();
            config.setMaxTotal(properties.getMaxActive());
            config.setMaxIdle(properties.getMaxIdle());
            config.setMinIdle(properties.getMinIdle());
            if (properties.getTimeBetweenEvictionRuns() != null) {
                config.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRuns().toMillis());
            }
            if (properties.getMaxWait() != null) {
                config.setMaxWaitMillis(properties.getMaxWait().toMillis());
            }
            return config;
        }
    }


    @Override
    public void setBeanFactory(@Nullable BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

    public RedisPropertiesAutoConfig getRedisProperties() {
        return redisProperties;
    }
}
  • 工厂实现类
@Configuration
public class LettuceRedisConnectionFactoryConfig extends AbstractRedisConnectionFactoryConfig {


    @Override
    protected RedisConnectionFactory buildRedisConnectionFactory(RedisProperties redisProperty) {
        if (redisProperty == null) {
            //创建默认的redis连接工厂
            LettuceConnectionFactory defaultConnectionFactory = createDefaultConnectionFactory();
            
            defaultConnectionFactory.afterPropertiesSet();
            return defaultConnectionFactory;
        }
        LettuceClientConfiguration clientConfig = buildLettuceClientConfiguration(DefaultClientResources.create(),
                redisProperty.getLettuce().getPool(), redisProperty);
        //创建lettuce连接工厂
        LettuceConnectionFactory redisConnectionFactory;
        if (getRedisMode(redisProperty) == RedisModeEnum.CLUSTER) {
            redisConnectionFactory = new LettuceConnectionFactory(new RedisClusterConfiguration
                    (redisProperty.getCluster().getNodes()), clientConfig);
        } else if (getRedisMode(redisProperty) == RedisModeEnum.SENTINEL) {
            redisConnectionFactory = new LettuceConnectionFactory(new RedisSentinelConfiguration
                    (redisProperty.getSentinel().getMaster(), new HashSet<>(redisProperty.getSentinel().getNodes())), clientConfig);
        } else {
            redisConnectionFactory = new LettuceConnectionFactory(new RedisStandaloneConfiguration
                    (redisProperty.getHost(), redisProperty.getPort()), clientConfig);
        }
       
        redisConnectionFactory.afterPropertiesSet();
        return redisConnectionFactory;
    }

    @Override
    protected RedisModeEnum getRedisMode(RedisProperties redisProperty) {
        if (redisProperty.getCluster() != null) {
            Assert.notNull(redisProperty.getCluster().getNodes(), "集群节点不能为空");
            return RedisModeEnum.CLUSTER;
        } else if (redisProperty.getSentinel() != null) {
            Assert.hasText(redisProperty.getSentinel().getMaster(), "哨兵的主节点不能为空");
            Assert.notNull(redisProperty.getSentinel().getNodes(), "哨兵的从节点不能为空");
            return RedisModeEnum.SENTINEL;
        }
        return RedisModeEnum.STAND_ALONE;
    }

    private LettuceClientConfiguration buildLettuceClientConfiguration(ClientResources clientResources, RedisProperties.Pool pool, RedisProperties redisProperties) {
        LettuceClientConfiguration.LettuceClientConfigurationBuilder builder = createBuilder(pool);
        applyProperties(builder, redisProperties);
        builder.clientResources(clientResources);
        return builder.build();
    }

    private LettuceClientConfiguration.LettuceClientConfigurationBuilder applyProperties(
            LettuceClientConfiguration.LettuceClientConfigurationBuilder builder, RedisProperties redisProperties) {
        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());
            }
        }
        return builder;
    }

    private LettuceClientConfiguration.LettuceClientConfigurationBuilder createBuilder(RedisProperties.Pool pool) {
        if (pool == null) {
            return LettuceClientConfiguration.builder();
        }
        return new RedisConnectionPoolBuilderFactory().createBuilder(pool);
    }

    private LettuceConnectionFactory createDefaultConnectionFactory() {
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration());
    }
}

5.redisTemplate的配置

public abstract class AbstractRedisConfiguration implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    protected RedisTemplate<String, Object> buildRedisTemplate(String name) {
        return buildRedisTemplate(name, new GenericJackson2JsonRedisSerializer(), false);
    }

    protected RedisTemplate<String, Object> buildRedisTemplate(String name, Boolean enableTransaction) {
        return buildRedisTemplate(name, new GenericJackson2JsonRedisSerializer(), enableTransaction);
    }

    protected RedisTemplate<String, Object> buildRedisTemplate(String name, RedisSerializer redisSerializer,
                                                               Boolean enableTransaction) {
        if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("redis properties name field must not null");
        }
        RedisConnectionFactory redisConnectionFactory = getRedisConnectionFactory(name);
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(redisSerializer);
        redisTemplate.setHashValueSerializer(redisSerializer);
        redisTemplate.setEnableTransactionSupport(enableTransaction);
        return redisTemplate;
    }


    private RedisConnectionFactory getRedisConnectionFactory(String name) {
        return (RedisConnectionFactory) applicationContext.getBean(name.trim() + "_redisConnectionFactory");
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
  • 配置redisTemplate
@Configuration
@DependsOn("lettuceRedisConnectionFactoryConfig")
public class RedisConfiguration extends AbstractRedisConfiguration {


    @Bean("developRedisTemplate")
    public RedisTemplate<String, Object> getDevelopRedisTemplate() {
        return buildRedisTemplate("develop");
    }

    @Bean("testRedisTemplate")
    public RedisTemplate<String, Object> getTestRedisTemplate() {
        return buildRedisTemplate("test");
    }
}
  • 下面利用spring boot的ApplicationRunner接口测试一下,用redis客户端查看发现结果已经存入进去了。
     @Autowired
    @Qualifier("developRedisTemplate")
    private RedisTemplate developRedisTemplate;

    @Autowired
    @Qualifier("testRedisTemplate")
    private RedisTemplate testRedisTemplate;


   @Override
    public void run(ApplicationArguments args) throws Exception {
        developRedisTemplate.opsForValue().set("develop_RedisMultiple", "test", 120, TimeUnit.SECONDS);
        testRedisTemplate.opsForValue().set("test_RedisMultiple", "test", 120, TimeUnit.SECONDS);
    }

以上是关于spring boot整合redis多实例的主要内容,如果未能解决你的问题,请参考以下文章

spring boot 整合 redis

Spring boot配置多个Redis数据源操作实例

Spring Boot 整合Redis 实现缓存

Spring Boot如何整合Redis

Spring Boot如何整合Redis

spring boot 整合 redis