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

网友投稿 1425 2023-05-18

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

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

核心代码

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

@Bean

@ConditionalOnMissingBean

public JedisConnectionFactory jedisConnectionFactory() {

JedisConnectionFactory factory = null;

String[] split = node.split(",");

Set 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.JedisClihttp://entConfiguration;

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 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 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 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 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 redisTemplate = new RedisTemplate();

redisTemplate.setConnectionFactory(jedisConnectionFactory);

RedisSerializer stringSerializer = newhsnprRW 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依赖

org.springframework.boot

spring-boot-starter-data-redis

${springboot.version}

org.springframework.boot

spring-boot-starter

provided

redis.clients

jedis

${redis.version}

com.fasterxml.jackson.core

jackson-annotations

provided

com.fasterxml.jackson.core

jackson-databind

provided

com.fasterxml.jackson.core

jackson-core

provided

配置文件

1.yml配置

1.1支持 Cluster模式 集群

node有多个redis的地址,以逗号分隔

如果redhttp://is没有密码直接去掉配置就可以了 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 redisTemplate;

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解使用Spring的BeanPostProcessor优雅的实现工厂模式
下一篇:SpringCloud通用请求字段拦截处理方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~