• Redis——Springboot集成Redis集群


    前言

    在 springboot 1.5.x版本的默认的Redis客户端是 Jedis实现的,springboot 2.x版本中默认客户端是用 lettuce实现的。

    Lettuce 与 Jedis 比较

    • Lettuce 和 Jedis 的都是连接 Redis Server的客户端。
    • Jedis 在实现上是直连 redis server,多线程环境下非线程安全,除非使用连接池,为每个 redis实例增加物理连接。
    • Lettuce 是 一种可伸缩,线程安全,完全非阻塞的Redis客户端,多个线程可以共享一个RedisConnection,它利用Netty NIO 框架来高效地管理多个连接,从而提供了异步和同步数据访问方式,用于构建非阻塞的反应性应用程序。

    使用Lettuce连接Redis集群

    • application文件
    ################ Redis 基础配置 ##############
    # Redis数据库索引(默认为0)
    spring.redis.database=0  
    # Redis服务器地址
    spring.redis.host=127.0.0.1
    # Redis服务器连接端口
    spring.redis.port=6379  
    # Redis服务器连接密码(默认为空)
    spring.redis.password=zwqh
    # 链接超时时间 单位 ms(毫秒)
    spring.redis.timeout=3000

    ################ Redis 线程池设置 ############## # 连接池最大连接数(使用负值表示没有限制) 默认 8 spring.redis.lettuce.pool.max-active=8 # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1 spring.redis.lettuce.pool.max-wait=-1 # 连接池中的最大空闲连接 默认 8 spring.redis.lettuce.pool.max-idle=8 # 连接池中的最小空闲连接 默认 0 spring.redis.lettuce.pool.min-idle=0
    • 自定义 RedisTemplate

    默认情况下的模板只能支持 RedisTemplate<String,String>,只能存入字符串,很多时候,我们需要自定义 RedisTemplate ,设置序列化器,这样我们可以很方便的操作实例对象。如下所示:

    @Configuration
    public class LettuceRedisConfig {
    
        @Bean
        public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
            RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            redisTemplate.setConnectionFactory(connectionFactory);
            return redisTemplate;
        }
    }
    • 序列化实体类

    public class UserEntity implements Serializable {
    
        private static final long serialVersionUID = 5237730257103305078L;
        
        private Long id;
        private String userName;
        private String userSex;
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getUserSex() {
            return userSex;
        }
        public void setUserSex(String userSex) {
            this.userSex = userSex;
        }    
    }
    • 单元测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringBootRedisApplicationTests {
    
        @Autowired
        private RedisTemplate<String, String> strRedisTemplate;
        @Autowired
        private RedisTemplate<String, Serializable> serializableRedisTemplate;
        
        @Test
        public void testString() {
            strRedisTemplate.opsForValue().set("strKey", "zwqh");
            System.out.println(strRedisTemplate.opsForValue().get("strKey"));
        }
        
        @Test
        public void testSerializable() {
            UserEntity user=new UserEntity();
            user.setId(1L);
            user.setUserName("朝雾轻寒");
            user.setUserSex("");        
            serializableRedisTemplate.opsForValue().set("user", user);        
            UserEntity user2 = (UserEntity) serializableRedisTemplate.opsForValue().get("user");
            System.out.println("user:"+user2.getId()+","+user2.getUserName()+","+user2.getUserSex());
        }
    
    }
    • 执行结果如下:

    使用Jedis连接Redis集群

    • pom文件
    <dependencies>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-web</artifactId>
           </dependency>
           <!-- lombok组件,需要你的IDE安装lombok插件,
                通过使用对应的注解,
                可以在编译源码的时候生成对应的方法,
                在这个例子中,
                @Data注解会在RedisConfig类中提供所有属性的getter和setter方法 -->
           <dependency>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok</artifactId>
               <optional>true</optional>
           </dependency>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-test</artifactId>
               <scope>test</scope>
           </dependency>
           <!--只有2.9.0才有密码设置-->
           <dependency>
               <groupId>redis.clients</groupId>
               <artifactId>jedis</artifactId>
               <version>2.9.0</version>
           </dependency>
           <!--使用commons-pool2连接池-->
           <dependency>
               <groupId>org.apache.commons</groupId>
               <artifactId>commons-pool2</artifactId>
           </dependency>
           <dependency>
               <groupId>com.alibaba</groupId>
               <artifactId>fastjson</artifactId>
           </dependency>
    • application文件
    spring:
      application:
        name: spring-boot-redis
      redis:
        #集群配置
        config:
          clusterNodes:
             - xx.xx.xxx.xxx:7001
             - xx.xx.xxx.xxx:7002
             - xx.xx.xxx.xxx:7003
             - xx.xx.xxx.xxx:7004
             - xx.xx.xxx.xxx:7005
             - xx.xx.xxx.xxx:7006
          connectionTimeout: 60000
          soTimeout: 3000
          maxAttempts: 1000
          password: 123456
    • redis属性配置类
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    import java.util.List;
    
    /**
     * @author: caoweixiong
     * @date: 2020/04/29
     * @description:
     */ 
    @Data
    @Component
    @ConfigurationProperties(prefix = "spring.redis.config")
    public class RedisConfig{
    
        /**
         * 集群节点
         */
        private List<String> clusterNodes;
    
        /**
         * 密码
         */
        private String password;
    
        /**
         * 连接超时时间
         */
        private int connectionTimeout;
    
        /**
         * 读取数据超时时间
         */
        private int soTimeout;
    
        /**
         * 最大尝试次数
         */
        private int maxAttempts;
    
    }
    • (JedisCluster属性配置、JedisPoolConfig属性配置)类
    import com.asiainfo.redis.utils.JedisClusterUtil;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import redis.clients.jedis.HostAndPort;
    import redis.clients.jedis.JedisCluster;
    import redis.clients.jedis.JedisPoolConfig;
    
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * @author: caoweixiong
     * @date: 2019/04/29
     * @description:
     */
    @Configuration
    public class JedisClusterConfig {
    
        @Autowired
        private RedisConfig redisConfig;
    
        private static Logger logger = LoggerFactory.getLogger(JedisClusterUtil.class);
    
        // 使用单例模式
        private static JedisCluster jedisCluster = null;
    
        @Bean
        public synchronized JedisCluster getJedisCluster() {
            try {
                logger.info(" >>>>>>> REDIS CLUSTER连接池,开始启动 >>>>>>> ");
                JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                jedisPoolConfig.setTestOnBorrow(true);
                jedisPoolConfig.setTestOnReturn(true);
                jedisPoolConfig.setTestOnCreate(true);
                jedisPoolConfig.setTestWhileIdle(true);
                jedisPoolConfig.setMaxTotal(300);
                jedisPoolConfig.setMinIdle(5);
                //一定要设置不然会一直等待获取连接导致线程阻塞
                jedisPoolConfig.setMaxWaitMillis(6000);
                //获得节点配置信息
                Set<HostAndPort> nodes = new HashSet<>();
                if (redisConfig.getClusterNodes() != null) {
                    for (String ipAndPort : redisConfig.getClusterNodes()) {
                        String[] ipOrPort = ipAndPort.split(":");
                        HostAndPort hostAndPort = new HostAndPort(ipOrPort[0], Integer.parseInt(ipOrPort[1]));
                        nodes.add(hostAndPort);
                    }
                }
                //初始化 只有当jedisCluster为空时才实例化
                if (jedisCluster == null&&nodes.size() > 0)  {
                    //redis有密码,配置JedisCluster
                    if (redisConfig.getPassword() != null) {
                        jedisCluster = new JedisCluster(nodes, redisConfig.getConnectionTimeout(), redisConfig.getSoTimeout(), redisConfig.getMaxAttempts(), redisConfig.getPassword(), jedisPoolConfig);
                    }
                    //redis无密码,配置JedisCluster
                    else {
                        jedisCluster = new JedisCluster(nodes, redisConfig.getConnectionTimeout(), redisConfig.getSoTimeout(), redisConfig.getMaxAttempts(), jedisPoolConfig);
                    }
                    logger.info(" >>>>>>> REDIS CLUSTER 连接池,启动成功 >>>>>> ");
                } else {
                    logger.warn("{} redis 连接异常", nodes);
                }
            } catch (Exception e) {
                logger.error(">>>>>> REDIS CLUSTER 连接池,初始化失败 >>>>>> ", e);
                e.printStackTrace();
            }
            return jedisCluster;
        }
    }
    • redis集群工具类
    import com.alibaba.fastjson.JSON;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.JedisCluster;
    
    import java.io.Serializable;
    
    /**
     * @author: caoweixiong
     * @date: 2020/04/29
     * @description: redis集群工具类
     */
    @Component
    public class JedisClusterUtil implements Serializable {
    
        @Autowired
        private JedisCluster jedisCluster;
    
        private static final long serialVersionUID = 1L;
    
        private static final Logger LOGGER = LoggerFactory.getLogger(JedisClusterUtil.class);
    
        /**
         *
         * @param key   缓存key
         * @param value 缓存value
         */
        public void set(String key, String value) {
            jedisCluster.set(key, value);
            LOGGER.debug("JedisClusterUtil:set cache key={},value={}", key, value);
        }
    
        /**
         * 设置缓存对象
         *
         * @param key 缓存key
         * @param obj 缓存value
         */
        public <T> void setObject(String key, T obj, int expireTime) {
            jedisCluster.setex(key, expireTime, JSON.toJSONString(obj));
        }
    
        /**
         * 获取指定key的缓存
         *
         * @param key---JSON.parseObject(value, User.class);
         */
        public String getObject(String key) {
            return jedisCluster.get(key);
        }
    
        /**
         * 判断当前key值 是否存在
         *
         * @param key
         */
        public boolean hasKey(String key) {
            return jedisCluster.exists(key);
        }
    
    
        /**
         * 设置缓存,并且自己指定过期时间
         *
         * @param key
         * @param value
         * @param expireTime 过期时间
         */
        public void setWithExpireTime(String key, String value, int expireTime) {
            jedisCluster.setex(key, expireTime, value);
            LOGGER.debug("JedisClusterUtil:setWithExpireTime cache key={},value={},expireTime={}", key, value, expireTime);
        }
    
    
        /**
         * 获取指定key的缓存
         *
         * @param key
         */
        public String get(String key) {
            String value = jedisCluster.get(key);
            LOGGER.debug("JedisClusterUtil:get cache key={},value={}", key, value);
            return value;
        }
    
        /**
         * 删除指定key的缓存
         *
         * @param key
         */
        public void delete(String key) {
            jedisCluster.del(key);
            LOGGER.debug("JedisClusterUtil:delete cache key={}", key);
        }
    }
    • redis集群测试类
    import com.asiainfo.redis.po.TestMan;
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisCluster;
    
    import java.util.List;
    
    import static org.junit.Assert.*;
    
    /**
     * @author: caoweixiong
     * @date: 2020/04/29
     * @description: redis集群测试类
     */
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class JedisClusterUtilTest {
    
        @Autowired
        JedisClusterUtil jedisClusterUtil;
    
        @Test
        public void set() {
            jedisClusterUtil.set("name", "jedis");
            Assert.assertEquals("jedis",jedisClusterUtil.get("name"));
        }
    
        @Test
        public void get() {
        }
    
        @Test
        public void setObject() {
            TestMan man = new TestMan();
            man.setId(10087L);
            man.setAge(35);
            man.setPassword("********");
            man.setSex(0);
            man.setUsername("cwx");
            jedisClusterUtil.setObject("10087L", man, 200);
            Assert.assertNotNull(jedisClusterUtil.getObject("10087L"));
        }
    
        @Test
        public void getObject() {
            System.out.println(jedisClusterUtil.getObject("10087L"));
        }
    
        @Test
        public void hasKey() {
        }
    
        @Test
        public void setWithExpireTime() {
        }
    
        @Test
        public void delete() {
            jedisClusterUtil.delete("10087L");
            Assert.assertEquals(null, jedisClusterUtil.get("10087L"));
        }
    }
  • 相关阅读:
    计算机网络 其他1
    C++ part9
    C++ part8
    操作系统 part5
    C++ part7
    MyXls导出Excel的各种设置
    C# excel操作
    Castle
    C# Keycode对照表
    IEnumerable.Select和SelectMany的区别
  • 原文地址:https://www.cnblogs.com/caoweixiong/p/12803210.html
Copyright © 2020-2023  润新知