SpringBoot Redis自适应配置的实现(Cluster Standalone Sentinel)

核心代码段

提供一个JedisConnectionFactory  根据配置来判断 单点 集群 还是哨兵

 @Bean
    @ConditionalOnMissingBean
    public JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory factory = null;

        String[] split = node.split(",");
        Set<HostAndPort> nodes = new LinkedHashSet<>();
        for (int i = 0; i < split.length; i++) {
            try {
                String[] split1 = split[i].split(":");
                nodes.add(new HostAndPort(split1[0], Integer.parseInt(split1[1])));
            } catch (Exception e) {
                throw new RuntimeException(String.format("出现配置错误!请确认node=[%s]是否正确", node));
            }
        }
        //获得默认的连接池构造器(怎么设计的,为什么不抽象出单独类,供用户使用呢) 有毒
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcb =
                (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        //指定jedisPoolConifig来修改默认的连接池构造器(真麻烦,滥用设计模式!) !!!!
        jpcb.poolConfig(jedisPoolConfig);
        //通过构造器来构造jedis客户端配置
        JedisClientConfiguration jedisClientConfiguration = jpcb.build();

        //如果是哨兵的模式
        if (!StringUtils.isEmpty(sentinel)) {
            logger.info("Redis use SentinelConfiguration");
            RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
            String[] sentinelArray = sentinel.split(",");
            for (String s : sentinelArray) {
                try {
                    String[] split1 = s.split(":");
                    redisSentinelConfiguration.addSentinel(new RedisNode(split1[0], Integer.parseInt(split1[1])));
                } catch (Exception e) {
                    throw new RuntimeException(String.format("出现配置错误!请确认node=[%s]是否正确", node));
                }
            }
            factory = new JedisConnectionFactory(redisSentinelConfiguration, jedisClientConfiguration);

        }
        //如果是单个节点 用Standalone模式
        else if (nodes.size() == 1) {
            logger.info("Redis use RedisStandaloneConfiguration");
            for (HostAndPort n : nodes) {
                RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
                if (!StringUtils.isEmpty(password)) {
                    redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
                }
                redisStandaloneConfiguration.setPort(n.getPort());
                redisStandaloneConfiguration.setHostName(n.getHost());
                factory = new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
            }
        }
        //集群配置信息实现
        else {
            logger.info("Redis use RedisStandaloneConfiguration");
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
            nodes.forEach(n -> {
                redisClusterConfiguration.addClusterNode(new RedisNode(n.getHost(), n.getPort()));
            });
            if (!StringUtils.isEmpty(password)) {
                redisClusterConfiguration.setPassword(RedisPassword.of(password));
            }
            redisClusterConfiguration.setMaxRedirects(maxRedirect);
            factory = new JedisConnectionFactory(redisClusterConfiguration, jedisClientConfiguration);
        }
        return factory;
    }

Configration

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisPoolConfig;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @Author foxzzz
 * @Class SelfAdaptionRedisConfig
 * @Description 自适应redis配置
 * 适用于 单点[主从]  哨兵模式  集群模式
 * @Date 2020/7/6 14:34
 */

@Configuration
@EnableCaching
public class SelfAdaptionRedisConfig<K, V> extends CachingConfigurerSupport {
    private final static Logger logger = LoggerFactory.getLogger(SelfAdaptionRedisConfig.class);

    @Value("${spring.redis.node}")
    private String node;
    @Value("${spring.redis.timeout:0}")
    private int timeout;
    @Value("${spring.redis.password:}")
    private String password;
    @Value("${spring.redis.sentinel:}")
    private String sentinel;

    @Value("${spring.redis.jedis.pool.max-total:8}")
    private int maxTotal;
    @Value("${spring.redis.jedis.pool.max-idle:8}")
    private int maxIdle;
    @Value("${spring.redis.jedis.pool.min-idle:0}")
    private int minIdle;
    @Value("${spring.redis.jedis.pool.max-wait:-1}")
    private long maxWaitMillis;
    @Value("${spring.redis.jedis.pool.test-on-borrow:true}")
    private boolean testOnBorrow;
    @Value("${spring.redis.jedis.factory.max-redirects:5}")
    private int maxRedirect;

    @Autowired
    private JedisPoolConfig jedisPoolConfig;
    @Autowired
    private JedisConnectionFactory jedisConnectionFactory;

    @Bean
    @ConditionalOnMissingBean
    @Override
    public CacheManager cacheManager() {
        // 初始化缓存管理器,在这里我们可以缓存的整体过期时间什么的,我这里默认没有配置
        logger.info("初始化 -> [{}]", "CacheManager RedisCacheManager Start");
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager
                .RedisCacheManagerBuilder
                .fromConnectionFactory(jedisConnectionFactory);
        return builder.build();
    }

    @Bean
    @ConditionalOnMissingBean
    @Override
    public CacheErrorHandler errorHandler() {
        // 异常处理,当Redis发生异常时,打印日志,但是程序正常走
        logger.info("初始化 -> [{}]", "Redis CacheErrorHandler");
        CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
                logger.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
            }

            @Override
            public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
                logger.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
            }

            @Override
            public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
                logger.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
            }

            @Override
            public void handleCacheClearError(RuntimeException e, Cache cache) {
                logger.error("Redis occur handleCacheClearError:", e);
            }
        };
        return cacheErrorHandler;
    }

    @Bean
    @ConditionalOnMissingBean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
        config.setMaxWaitMillis(maxWaitMillis);
        //最小空闲连接数, 默认0
        config.setMinIdle(minIdle);
        // 最大空闲连接数, 默认8个
        config.setMaxIdle(maxIdle);
        // 最大连接数, 默认值8个
        config.setMaxTotal(maxTotal);
        //对拿到的connection进行validateObject校验
        config.setTestOnBorrow(testOnBorrow);
        return config;
    }

//    private JedisCluster getJedisCluster() {
//        String[] split = node.split(",");
//        Set<HostAndPort> nodes = new LinkedHashSet<>();
//        for (int i = 0; i < split.length; i++) {
//            try {
//                String[] split1 = split[i].split(":");
//                nodes.add(new HostAndPort(split1[0], Integer.parseInt(split1[1]))));
//            } catch (Exception e) {
//            }
//        }
//        JedisCluster jedisCluster = null;
//        if (StringUtils.isEmpty(password)) {
//            jedisCluster = new JedisCluster(nodes, 5000, 3000, 10, jedisPoolConfig);
//        } else {
//            jedisCluster = new JedisCluster(nodes, 5000, 3000, 10, password, jedisPoolConfig);
//        }
//    }

    @Bean
    @ConditionalOnMissingBean
    public JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory factory = null;

        String[] split = node.split(",");
        Set<HostAndPort> nodes = new LinkedHashSet<>();
        for (int i = 0; i < split.length; i++) {
            try {
                String[] split1 = split[i].split(":");
                nodes.add(new HostAndPort(split1[0], Integer.parseInt(split1[1])));
            } catch (Exception e) {
                throw new RuntimeException(String.format("出现配置错误!请确认node=[%s]是否正确", node));
            }
        }
        //获得默认的连接池构造器(怎么设计的,为什么不抽象出单独类,供用户使用呢) 有毒
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcb =
                (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        //指定jedisPoolConifig来修改默认的连接池构造器(真麻烦,滥用设计模式!) !!!!
        jpcb.poolConfig(jedisPoolConfig);
        //通过构造器来构造jedis客户端配置
        JedisClientConfiguration jedisClientConfiguration = jpcb.build();

        //如果是哨兵的模式
        if (!StringUtils.isEmpty(sentinel)) {
            logger.info("Redis use SentinelConfiguration");
            RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
            String[] sentinelArray = sentinel.split(",");
            for (String s : sentinelArray) {
                try {
                    String[] split1 = s.split(":");
                    redisSentinelConfiguration.addSentinel(new RedisNode(split1[0], Integer.parseInt(split1[1])));
                } catch (Exception e) {
                    throw new RuntimeException(String.format("出现配置错误!请确认node=[%s]是否正确", node));
                }
            }
            factory = new JedisConnectionFactory(redisSentinelConfiguration, jedisClientConfiguration);

        }
        //如果是单个节点 用Standalone模式
        else if (nodes.size() == 1) {
            logger.info("Redis use RedisStandaloneConfiguration");
            for (HostAndPort n : nodes) {
                RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
                if (!StringUtils.isEmpty(password)) {
                    redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
                }
                redisStandaloneConfiguration.setPort(n.getPort());
                redisStandaloneConfiguration.setHostName(n.getHost());
                factory = new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
            }
        }
        //集群配置信息实现
        else {
            logger.info("Redis use RedisStandaloneConfiguration");
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
            nodes.forEach(n -> {
                redisClusterConfiguration.addClusterNode(new RedisNode(n.getHost(), n.getPort()));
            });
            if (!StringUtils.isEmpty(password)) {
                redisClusterConfiguration.setPassword(RedisPassword.of(password));
            }
            redisClusterConfiguration.setMaxRedirects(maxRedirect);
            factory = new JedisConnectionFactory(redisClusterConfiguration, jedisClientConfiguration);
        }
        return factory;
    }

    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
        //设置序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        RedisSerializer stringSerializer = new StringRedisSerializer();
        // key序列化
        redisTemplate.setKeySerializer(stringSerializer);
        // value序列化
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // Hash key序列化
        redisTemplate.setHashKeySerializer(stringSerializer);
        // Hash value序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

pom依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>${springboot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${redis.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

配置文件

1.yml配置

1.1支持 Cluster模式 集群

  • node有多个redis的地址,以逗号分隔
  • 如果redis没有密码直接去掉配置就可以了 yml配置
spring:
  redis:
    node: 127.0.0.1:1001,127.0.0.1:1002,127.0.0.1:1003
    password: 123456

properties配置

  • spring.redis.node=127.0.0.1:1001,127.0.0.1:1002,127.0.0.1:1003
  • spring.redis.password=123456

1.2支持 Standalone模式 单点

node里只有一个redis地址的时候,会自动变成单点模式 yml配置

spring:
  redis:
    node: 127.0.0.1:1001
    password: 123456

properties配置

spring.redis.node=127.0.0.1:1001
spring.redis.password=123456

1.3支持 Sentinel模式 哨兵

当配置上sentinel以后就变成了哨兵模式 多个哨兵可以以逗号分割 yml配置

spring:
  redis:
    node: 127.0.0.1:1001
    sentinel:127.0.0.1:1002,127.0.0.1:1003
    password: 123456

properties配置

spring.redis.node=127.0.0.1:1001
spring.redis.sentinel:127.0.0.1:1002,127.0.0.1:1003
spring.redis.password=123456

1.4覆盖默认配置

如果没有配置这些信息,就会走默认配置 也可以在properties或者yml覆盖默认配置

#最大连接数, 默认值8个
spring.redis.jedis.pool.max-total=8
#最大空闲连接数, 默认8个
spring.redis.jedis.pool.max-idle=8
#最小空闲连接数, 默认0
spring.redis.jedis.pool.min-idle=0
#获取连接时的最大等待毫秒数,如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
spring.redis.jedis.pool.max-wait=-1
#对拿到的connection进行validateObject校验
spring.redis.jedis.pool.test-on-borrow=true
#集群时最大重定向个数默认5
spring.redis.jedis.factory.max-redirects=5

使用

代码使用

 @Autowired
 private RedisTemplate<String, Object> redisTemplate;

到此这篇关于SpringBoot Redis自适应配置的实现(Cluster Standalone Sentinel)的文章就介绍到这了,更多相关SpringBoot Redis自适应配置内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot项目中使用redis的配置详解

    程序结构: 一.配置 1. 在pom.xml中添加依赖 pom.xml文件如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=&q

  • 基于SpringBoot2.0默认使用Redis连接池的配置操作

    SpringBoot2.0默认采用Lettuce客户端来连接Redis服务端的 默认是不使用连接池的,只有配置 redis.lettuce.pool下的属性的时候才可以使用到redis连接池 redis: cluster: nodes: ${redis.host.cluster} password: ${redis.password} lettuce: shutdown-timeout: 100 # 关闭超时时间 pool: max-active: 8 # 连接池最大连接数(使用负值表示没有限制

  • 详解SpringBoot Redis自适应配置(Cluster Standalone Sentinel)

    核心代码段 提供一个JedisConnectionFactory  根据配置来判断 单点 集群 还是哨兵 @Bean @ConditionalOnMissingBean public JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory factory = null; String[] split = node.split(","); Set<HostAndPort> nodes =

  • 在SpringBoot中添加Redis及配置方法

    在实际的开发中,会有这样的场景.有一个微服务需要提供一个查询的服务,但是需要查询的数据库表的数据量十分庞大,查询所需要的时间很长. 此时就可以考虑在项目中加入缓存. 引入依赖 在maven项目中引入如下依赖.并且需要在本地安装redis. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifac

  • 详解springboot配置多个redis连接

    一.springboot nosql 简介 Spring Data提供其他项目,用来帮你使用各种各样的NoSQL技术,包括MongoDB, Neo4J, Elasticsearch, Solr, Redis,Gemfire, Couchbase和Cassandra.Spring Boot为Redis, MongoDB, Elasticsearch, Solr和Gemfire提供自动配置.你可以充分利用其他项目,但你需要自己配置它们. 1.1.Redis Redis是一个缓存,消息中间件及具有丰富

  • SpringBoot+redis配置及测试的方法

    1.创建项目时选择redis依赖 2.修改配置文件,使用SpringBoot就避免了之前很多的xml文件 2.1学过redis的同学都知道这个东西有集群版也有单机版,无论哪个版本配置起来都很简单 2.1.1首先找到配置文件 2.1.2然后配置集群版,直接在配置文件内编辑即可 2.1.3配置单机版 3.测试 找到测试文件夹,自动注入redis模板 4.分别测试操作String和Hash类型的数据 4.1操作String @Test public void testString(){ //操作Str

  • SpringBoot Redis自适应配置的实现(Cluster Standalone Sentinel)

    核心代码段 提供一个JedisConnectionFactory  根据配置来判断 单点 集群 还是哨兵 @Bean @ConditionalOnMissingBean public JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory factory = null; String[] split = node.split(","); Set<HostAndPort> nodes =

  • springboot redis使用lettuce配置多数据源的实现

    目前项目上需要连接两个redis数据源,一个redis数据源是单机模式,一个redis数据源是分片集群模式,这里将具体配置列一下. 项目用的springboot版本为 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</ver

  • Springboot 引入 Redis 并配置序列化并封装RedisTemplate 

    目录 前言 一.引入依赖 二.配置yml 三.封装RedisTemplate 四.controller使用RedisUtil 五.操作演示 前言 为什么要配置序列化:如果不配置序列化的话,我们在redis数据库中存储的数据可能以乱码形式显示出来,不方便我们判断数据存储的正确性,说白了就是序列化以后存进去的是什么,查询出来的就是什么,否则我们的键值都会变成一串看不懂的乱码. 为什么要封装RedisTemplate,因为如果不进行封装的话,大家请看,是不是有黄色的警告信息,看着起来很不舒服,Redi

  • 详解SpringBoot和Mybatis配置多数据源

    目前业界操作数据库的框架一般是 Mybatis,但在很多业务场景下,我们需要在一个工程里配置多个数据源来实现业务逻辑.在SpringBoot中也可以实现多数据源并配合Mybatis框架编写xml文件来执行SQL.在SpringBoot中,配置多数据源的方式十分便捷, 下面开始上代码: 在pom.xml文件中需要添加一些依赖 <!-- Spring Boot Mybatis 依赖 --> <dependency> <groupId>org.mybatis.spring.b

  • Redis安装配置与常用命令

    Redis简介 Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理.  它支持字符串.哈希表.列表.集合.有序集合,位图,hyperloglogs等数据类型.  内置复制.Lua脚本.LRU收回.事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区.    简言之,Redis是一种面向"键/值"对数据类型的内存数据库,可以满足我们对海量数据的快速读写需求.    Red

  • springboot 多环境配置教程

    在上一课中我们通过idea工具没有做任何配置就构建了一个springboot项目,并且已经成功启动了,但我们都很清楚这些都远远不能达到我们实际项目的需求,比如我们要引入我们自己的redis配置.mysql配置等,应该如何处理呢?在spring mvc中我们都是通过spring.xml相关文件配置,在springboot中这些都已经不存在了,我们应该怎样配置呢?别急,马上为大家揭晓谜底,跟着我一起来吧! NO1.我们在做项目的时候是不是都会区分很多环境呢?比如开发环境.测试环境.生产环境等,那么第

随机推荐