金麟岂是池中物,一遇风云便化龙

前言

  微服务如今的发展趋已然是势不可挡,并且业内已经有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传送门:git@github.com:MarsMuse/ArtisanCloud.git

写在最后

  这是作者从业来的第一篇博客,写的不好的地方还请各位见谅,如果这篇博客能够为您带来哪怕是丝毫帮助,我也深感荣幸。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐