SpringBoot使用Jedis整合Redis集群

248 阅读3分钟

前言

默认springboot使用lettuce作为redis客户端,但是有些低版本的springboot直接使用lettuce连接redis集群会有版本不兼容的问题。故只能采用Jedis来整合redis集群

源代码: # springboot-example 项目 redis-cluster-jedis 分支

步骤

  1. 依赖

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    
        <spring.boot.version>2.2.5.RELEASE</spring.boot.version>
        <jedis.version>3.1.0</jedis.version>
        <fastjson.version>1.2.68</fastjson.version>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <!-- 统一依赖管理 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${jedis.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    
  2. 配置文件application.properties

    #redis集群配置
    spring.redis.nodes=master:6379,master:6380,node1:6379,node1:6380,node2:6379,node2:6380,
    #重定向的最大次数  (意义:重定向的最大数量,比如第一台挂了,连第二台,第二台挂了连第三台,这个重新连接的最大数量)
    spring.redis.maxRedirects=3
    #如果有密码
    spring.redis.password=xxxxxx
    #客户端超时时间单位是毫秒 默认是2000
    spring.redis.timeout=10000
    #最大空闲数
    spring.redis.maxIdle=10
    #连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
    #redis.maxActive=600
    #控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
    spring.redis.maxTotal=300
    #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
    spring.redis.maxWaitMillis=3000
    #连接的最小空闲时间 默认1800000毫秒(30分钟)
    spring.redis.minEvictableIdleTimeMillis=300000
    #每次释放连接的最大数目,默认3
    spring.redis.numTestsPerEvictionRun=1024
    #逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
    spring.redis.timeBetweenEvictionRunsMillis=30000
    #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
    spring.redis.testOnBorrow=true
    #在空闲时检查有效性, 默认false
    spring.redis.testWhileIdle=true
    
  3. Redis配置类RedisConfig

    @Configuration
    public class RedisConfig {
    
        @Autowired
        private RedisProperties redisProperties;
    
        /**
         * JedisPoolConfig 连接池
         *
         * @return
         */
        @Bean(name="jedis.pool.config")
        public JedisPoolConfig jedisPoolConfig() {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // 最大空闲数
            jedisPoolConfig.setMaxIdle(redisProperties.getMaxIdle());
            // 连接池的最大数据库连接数
            jedisPoolConfig.setMaxTotal(redisProperties.getMaxTotal());
            // 最大建立连接等待时间
            jedisPoolConfig.setMaxWaitMillis(redisProperties.getMaxWaitMillis());
            // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
            jedisPoolConfig.setMinEvictableIdleTimeMillis(redisProperties.getMinEvictableIdleTimeMillis());
            // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
            jedisPoolConfig.setNumTestsPerEvictionRun(redisProperties.getNumTestsPerEvictionRun());
            // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
            jedisPoolConfig.setTimeBetweenEvictionRunsMillis(redisProperties.getTimeBetweenEvictionRunsMillis());
            // 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
            jedisPoolConfig.setTestOnBorrow(redisProperties.isTestOnBorrow());
            // 在空闲时检查有效性, 默认false
            jedisPoolConfig.setTestWhileIdle(redisProperties.isTestWhileIdle());
            return jedisPoolConfig;
        }
    
        /**
         * 集群redis配置
         * @return
         */
        @Bean("redis.cluster.config")
        public RedisClusterConfiguration redisClusterConfiguration(){
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
            String[] serverHost=redisProperties.getNodes().split(",");
            if (serverHost.length<1){
                throw new RuntimeException("请您设置redis服务器配置信息");
            }
            Set<RedisNode> ipNode = new HashSet<>();
            for (String ipAndPorts : serverHost) {
                String[] ipAndPost=ipAndPorts.split(":");
                ipNode.add(new RedisNode(ipAndPost[0].trim(), Integer.valueOf(ipAndPost[1])));
            }
            redisClusterConfiguration.setClusterNodes(ipNode);
            redisClusterConfiguration.setPassword(redisProperties.getPassword());
            redisClusterConfiguration.setMaxRedirects(redisProperties.getMaxRedirects());
            return redisClusterConfiguration;
        }
    
        /**
         * 集群版  factory
         * @param config
         * @param jedisPoolConfig
         * @return
         */
        @Bean(name = "jedis.cluster.factory")
        public JedisConnectionFactory JedisClusterConnectionFactory(RedisClusterConfiguration config,JedisPoolConfig jedisPoolConfig) {
            return new JedisConnectionFactory(config,jedisPoolConfig);
        }
    
    
        /**
         * 实例化 RedisTemplate 对象
         *  使用单机版 @Qualifier("jedis.standalone.factory");使用集群版 @Qualifier("jedis.cluster.factory")
         * @return
         */
        @Bean(name = "redisTemplate")
        @Autowired
        public RedisTemplate<String, Object> functionDomainRedisTemplate(@Qualifier("jedis.cluster.factory") JedisConnectionFactory jedisConnectionFactory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            initDomainRedisTemplate(redisTemplate, jedisConnectionFactory);
            return redisTemplate;
        }
    
        /**
         * 设置数据存入 redis 的序列化方式,并开启事务
         *
         * @param redisTemplate
         * @param factory
         */
        private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, JedisConnectionFactory factory) {
            // 使用 GenericFastJsonRedisSerializer 替换默认序列化
            GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
            // 设置key和value的序列化规则
            redisTemplate.setKeySerializer(new GenericToStringSerializer<>(Object.class));
            redisTemplate.setValueSerializer(genericFastJsonRedisSerializer);
            // 设置hashKey和hashValue的序列化规则
            redisTemplate.setHashKeySerializer(new GenericToStringSerializer<>(Object.class));
            redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer);
            // 开启事务
            redisTemplate.setEnableTransactionSupport(true);
            redisTemplate.setConnectionFactory(factory);
            //调用后初始化方法,没有它将抛出异常
            redisTemplate.afterPropertiesSet();
        }
    }
    
  4. 配置类对象RedisProperties

    @Data
    @Component
    @ConfigurationProperties(prefix = "spring.redis")
    public class RedisProperties {
    
        private String nodes;
    
        private Integer maxRedirects;
    
        private String password;
    
        private int timeout;
    
        private Integer maxIdle;
    
        private Integer maxTotal;
    
        private Integer maxWaitMillis;
    
        private Integer minEvictableIdleTimeMillis;
    
        private Integer numTestsPerEvictionRun;
    
        private long timeBetweenEvictionRunsMillis;
    
        private boolean testOnBorrow;
    
        private boolean testWhileIdle;
    }
    
  5. 测试代码

    @RestController
    public class HelloController {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @RequestMapping("/setHello")
        public String setHello(){
            redisTemplate.opsForValue().set("hello","world");
            return "OK!";
        }
    
        @RequestMapping("/getHello")
        public String getHello(){
            return (String) redisTemplate.opsForValue().get("hello");
        }
    }
    

如果想看哨兵、单机的整合,可以参考:www.sunofbeach.net/a/146549777…