SpringBoot整合Redis(Sentinel模式)

金麟豈是池中物,一遇風雲便化龍

前言

  微服務如今的發展趨已然是勢不可擋,並且業內已經有DubboSpringCloud等優秀的開源框架,可以說發展的已經是非常成熟了,所以決定順應技術發展浪潮,放棄老舊而臃腫的SSM,轉而搭建以SpringCloud爲基礎的微服務應用。
  通過Redis實現緩存與應用集羣間的Session共享是很成熟的應用緩存層解決方案,所以在框架搭建過程中必然是需要整合Redis,並且通過Redis的Sentinel實現了Redis的高可用。在整合Redis的過程中始終沒有找到比較好用的解決方案,看過很多博客,發現都不是自己想要的,所以索性決定自己來寫一個,僅供參考。

依賴注入

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

項目路徑如下

這裏寫圖片描述

redis.properties

  雖然SpringCloud簡化項目配置,但是絕對不是要求研發人員在項目中不可以使用配置,還是那句話約定大於配置,習慣大於約定。所以我們在項目中建立redis.properties用於配置Redis服務。

redis.nodes=192.168.1.205:26379,192.168.1.206:26379,192.168.1.207:26379
redis.masterName=artisanRedis
redis.password=abc123456
redis.maxTotal=10000
redis.maxIdle=100
redis.minIdle=50
redis.timeout=30000

RedisConfig

  SpringCloud給我們帶了很多開箱即用的工具,能夠讓我們的代碼更加的優雅。@ConfigurationProperties 讓我們不再爲讀取配置文件而感到煩惱,在SpringBoot 1.5+後需要配合@PropertySource使用,RedisConfig.java便優雅的讀取了Redis配置文件。

package com.artisan.redis.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**  
 *    
 * @author Fire Monkey 
 * @date 2018/3/12 下午6:25
 * Redis配置文件
 * 
 */ 
@Component
@PropertySource("classpath:conf/redis.properties")
@ConfigurationProperties(prefix = "redis")
public class RedisConfig {

    /**
     * 節點名稱
     */
    private String nodes;

    /**
     * Redis服務名稱
     */
    private String masterName;

    /**
     * 密碼
     */
    private String password;

    /**
     * 最大連接數
     */
    private int maxTotal;

    /**
     * 最大空閒數
     */
    private int maxIdle;

    /**
     * 最小空閒數
     */
    private int minIdle;

    /**
     * 連接超時時間
     */
    private int timeout;



    public String getNodes() {
        return nodes;
    }

    public void setNodes(String nodes) {
        this.nodes = nodes;
    }

    public String getMasterName() {
        return masterName;
    }

    public void setMasterName(String masterName) {
        this.masterName = masterName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getMaxTotal() {
        return maxTotal;
    }

    public void setMaxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public int getMinIdle() {
        return minIdle;
    }

    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    @Override
    public String toString() {
        return "RedisConfig{" +
                "nodes='" + nodes + '\'' +
                ", masterName='" + masterName + '\'' +
                ", password='" + password + '\'' +
                ", maxTotal='" + maxTotal + '\'' +
                ", maxIdle='" + maxIdle + '\'' +
                ", minIdle='" + minIdle + '\'' +
                ", timeout='" + timeout + '\'' +
                '}';
    }
}

RedisInitConfig

  簡約配置問風格讓我們不能再像從前一樣,隨心所欲的在Spring.xml文件中實例化某個Bean,但是註解@Bean卻爲我們打開了一扇窗。RedisInitConfig.java文件中創建了JedisPoolConfig,JedisSentinelPool這兩個重要的對象,爲後面RedisService對外提供Jedis奠定了基礎。

package com.artisan.redis.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;

import java.util.HashSet;
import java.util.Set;

/**  
 *    
 * @author Fire Monkey 
 * @date 2018/3/12 下午6:28
 * redis初始化配置
 * 
 */ 
@Configuration
public class RedisInitConfig {

    /**
     * 日誌打印對象
     */
    private Logger log = LoggerFactory.getLogger(RedisInitConfig.class);

    /**
     * 注入配置文件信息
     */
    @Autowired
    private RedisConfig redisConfig;


    /**  
     *    
     * @author Fire Monkey 
     * @date 2018/3/12 下午6:53
     * @return redis.clients.jedis.JedisPoolConfig
     * 初始化連接池配置對象
     *
     */ 
    @Bean(value = "jedisPoolConfig")
    public JedisPoolConfig initJedisPoolConfig(){
        log.info("JedisPool initialize start ...");
        JedisPoolConfig config = new JedisPoolConfig();

        //最大總量
        config.setMaxTotal(redisConfig.getMaxTotal());
        //設置最大空閒數量
        config.setMaxIdle(redisConfig.getMaxIdle());
        //設置最小空閒數量
        config.setMinIdle(redisConfig.getMinIdle());
        //常規配置
        config.setTestOnBorrow(true);
        config.setTestOnReturn(true);
        log.info("JedisPool initialize end ...");
        return config;
    }

    /**
     *
     * @author Fire Monkey
     * @date 下午7:20
     * @return redis.clients.jedis.JedisSentinelPool
     * 生成JedisSentinelPool並且放入Spring容器
     *
     */
    @Bean(value = "sentinelPool")
    public JedisSentinelPool initJedisPool(@Qualifier(value = "jedisPoolConfig") JedisPoolConfig jedisPoolConfig){

        Set<String>  nodeSet = new HashSet<>();
        //獲取到節點信息
        String nodeString = redisConfig.getNodes();
        //判斷字符串是否爲空
        if(nodeString == null || "".equals(nodeString)){
            log.error("RedisSentinelConfiguration initialize error nodeString is null");
            throw new RuntimeException("RedisSentinelConfiguration initialize error nodeString is null");
        }
        String[] nodeArray = nodeString.split(",");
        //判斷是否爲空
        if(nodeArray == null || nodeArray.length == 0){
            log.error("RedisSentinelConfiguration initialize error nodeArray is null");
            throw new RuntimeException("RedisSentinelConfiguration initialize error nodeArray is null");
        }
        //循環注入至Set中
        for(String node : nodeArray){
            log.info("Read node : {}。" , node);
            nodeSet.add(node);
        }
        //創建連接池對象
        JedisSentinelPool jedisPool = new JedisSentinelPool(redisConfig.getMasterName() ,nodeSet ,jedisPoolConfig ,redisConfig.getTimeout() , redisConfig.getPassword());

        return jedisPool;
    }
}

RedisService

  前面已經將JedisSentinelPool實例化,RedisService只需要將該對象注入,通過JedisSentinelPool獲取到Jedis,對外提供緩存服務,至此SpringCloud整合Jedis結束。

package com.artisan.redis.service;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisConnectionException;


/**  
 *    
 * @author Fire Monkey 
 * @date 2018/3/12 下午7:32
 * Reids工具通過Jedis實現與Redis交互
 * 
 */ 
@Component
public class RedisService {


    /**
     * 日誌打印對象
     */
    private static Logger log = Logger.getLogger(RedisService.class);


    /**
     * Jedis對象池 所有Jedis對象均通過該池租賃獲取
     */
    private static JedisSentinelPool sentinelPool;

    /**
     * 緩存數據成功
     */
    private final static String CACHE_INFO_SUCCESS = "OK";


    /**  
     *    
     * @author Fire Monkey 
     * @date 2018/3/12 下午7:34
     * 注入JedisSentinelPool
     *
     */ 
    @Autowired
    public  void setSentinelPool(JedisSentinelPool sentinelPool) {
        RedisService.sentinelPool = sentinelPool;
    }



    /**  
     *    
     * @author Fire Monkey 
     * @date 2018/3/12 下午7:35
     * @return redis.clients.jedis.Jedis
     * 獲取到Jedis
     *
     */ 
    private static Jedis getJedis()  {
        Jedis jedis;
        try {
            jedis = sentinelPool.getResource();
            return  jedis;
        } catch (JedisConnectionException e) {
            log.error("獲取Redis 異常", e);
            throw e;
        }
    }

    /**
     *
     * @author Fire Monkey 
     * @date 2018/3/12 下午7:36
     * 緩存String類型的數據,數據不過期
     *
     */
    public static boolean setString(String key, String value) throws Exception {
        return setString(key, value, -1);
    }


    /**
     *
     * @author Fire Monkey 
     * @date 2018/3/12 下午7:40
     * 緩存String類型的數據並設置超時時間
     *
     */
    public static boolean setString(String key, String value, int timeout) throws Exception {
        String result;
        Jedis jedis = null;
        try {
            jedis = getJedis();
            result = jedis.set(key, value);
            if (timeout != -1) {
                jedis.expire(key, timeout);
            }
            if (CACHE_INFO_SUCCESS.equals(result)) {
                return true;
            } else {
                return  false;
            }
        } finally {
            releaseRedis(jedis);
        }
    }

    /**
     *
     * @author Fire Monkey 
     * @date 2018/3/12 下午7:46
     * 獲取String類型的數據
     *
     */
    public static  String getString(String key) throws Exception {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.get(key);
        } catch (Exception e) {
            throw e;
        } finally {
            releaseRedis(jedis);
        }
    }


    /**  
     *    
     * @author Fire Monkey 
     * @date 2018/3/12 下午7:49
     * @return void
     * 釋放Jedis
     *
     */ 
    public static void releaseRedis(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }


    /**  
     *    
     * @author Fire Monkey 
     * @date 2018/3/12 下午7:55
     * @return boolean
     * 通過key刪除緩存中數據
     *
     */ 
    public static boolean del(String key) throws Exception {
        Long num;
        Jedis jedis = null;
        Boolean result = false;
        try {
            jedis = getJedis();
            num = jedis.del(key);
            if (num.equals(1L)) {
                result = true;
            }
        }finally {
            releaseRedis(jedis);
        }
        return result;
    }
}

GitHub地址

  github傳送門:[email protected]:MarsMuse/ArtisanCloud.git

寫在最後

  這是作者從業來的第一篇博客,寫的不好的地方還請各位見諒,如果這篇博客能夠爲您帶來哪怕是絲毫幫助,我也深感榮幸。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章