java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring多个redis数据源

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

作者:亚林瓜子

Spring项目集成双Redis数据源需配置两个连接工厂与RedisTemplate,通过@Primary指定默认Bean,@Qualifier注入特定Bean,支持集群环境,本文给大家介绍Spring工程中集成多个redis数据源的相关知识,感兴趣的朋友一起看看吧

问题

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

思路

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

解决

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;
        // 根据是否是集群模式选择不同的配置
        if (!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);
            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 redisProperties) {
        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("fhRedisTemplate")
private RedisTemplate<String, Integer> fhRedisTemplate;

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

@Resource
public RedisTemplate redisTemplate;

总结

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

参考

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

您可能感兴趣的文章:
阅读全文