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"));
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM