SpringBoot Redis自适应配置[Cluster Standalone Sentinel]

   日期:2020-07-08     浏览:108    评论:0    
核心提示:核心代码段提供一个JedisConnectionFactory 根据配置来判断 单点 集群 还是哨兵 @Bean @ConditionalOnMissingBean public JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory factory = null; String[] split = node.split(,); Set&.

核心代码段

提供一个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;



@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;
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服