1场景
当我们项目中集成了Redis时,但是Redis架构可能随着项目的大小、数据量、业务量等等进行变化。我们在做架构时,可能需要兼容三种模式,当项目想要选择单机、哨兵、集群时可以进行无缝切换。
2实现
完成以后,可通过配置文件指定对应的模式即可。上代码
Maven依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.1</version>
</dependency>
Spring配置文件关于Redis部分的配置
# redis
spring.redis.database=0
spring.redis.host=192.168.50.130
spring.redis.port=6379
spring.redis.password=enginex123
#连接超时时间(毫秒)
spring.redis.timeout=6000
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=3000
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=1000
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=100
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=5
# 集群模式配置
#最大重定向次数
spring.redis.cluster.max-redirects=5
#集群节点列表
spring.redis.cluster.nodes=192.168.0.10:6380,192.168.0.10:6381,192.168.0.10:6382,192.168.0.11:6380,192.168.0.11:6381,192.168.0.11:6382
# 哨兵模式配置
#哨兵服务的密码,可能与redis本身密码是不用的,具体在sentinel配置文件里配置
spring.redis.sentinel.password=enginex123
#主节点名称
spring.redis.sentinel.master=masterRedis
#Sentinel节点列表
spring.redis.sentinel.nodes=192.168.50.130:26379
#redis环境模式 standalone:单机 cluster:集群 sentinel:哨兵
redis.model = sentinel
读取Redis属性配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author lisw
* 微信公众号 ,走进Java
* @description redis配置
* @createDate 2022-11-01 16:23:40
**/
@Data
@Configuration
@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private String host;
private Integer port;
private String password;
private Integer database;
private int timeout;
private Cluster cluster;
private Sentinel sentinel;
public static class Cluster {
private List<String> nodes;
private Integer maxRedirects;
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
public Integer getMaxRedirects() {
return maxRedirects;
}
public void setMaxRedirects(Integer maxRedirects) {
this.maxRedirects = maxRedirects;
}
}
public static class Sentinel{
private List<String> nodes;
private String master;
private String password;
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
public String getMaster() {
return master;
}
public void setMaster(String master) {
this.master = master;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}
读取Jedis属性配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* @author lisw
* 微信公众号 ,走进Java
* @description redis配置
* @createDate 2022-11-01 16:26:16
**/
@Data
@Configuration
@Component
@ConfigurationProperties(prefix = "spring.redis.jedis.pool")
public class JedisProperties {
private Integer maxIdle;
private Integer maxWait;
private Integer minIdle;
private Integer maxActive;
}
Jedis 三种模式的Bean注入
SpringBoot,Jedis Bean注入,通过配置文件里面的redis.model
属性决定使用什么模式,注入什么Bean,利用@ConditionalOnProperty
注解
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.*;
import java.util.HashSet;
import java.util.Set;
/**
* @author lisw
* 微信公众号 ,走进Java
* @description Redis Bean
* @createDate 2022-11-01 16:27:56
**/
@Configuration
public class RedisConfig {
@Autowired
private RedisProperties redisProperties;
@Autowired
private JedisProperties jedisProperties;
@ConditionalOnProperty(value = "redis.model",havingValue = "standalone",matchIfMissing = true)
@Bean
public JedisPool redisPoolFactory() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(jedisProperties.getMaxIdle());
jedisPoolConfig.setMaxWaitMillis(jedisProperties.getMaxWait());
if (StringUtils.isNotBlank(redisProperties.getPassword())) {
return new JedisPool(jedisPoolConfig, redisProperties.getHost(), redisProperties.getPort(), redisProperties.getTimeout(), redisProperties.getPassword(), redisProperties.getDatabase());
} else {
return new JedisPool(jedisPoolConfig, redisProperties.getHost(), redisProperties.getPort(), redisProperties.getTimeout(), null, redisProperties.getDatabase());
}
}
@ConditionalOnProperty(value = "redis.model",havingValue = "sentinel",matchIfMissing = false)
@Bean
public JedisSentinelPool jedisSentinelPool(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(jedisProperties.getMaxIdle());
jedisPoolConfig.setMaxWaitMillis(jedisProperties.getMaxWait());
// 截取集群节点
String[] sentinels = redisProperties.getSentinel().getNodes().toArray(new String[0]);
// 创建set集合
Set<String> nodes = new HashSet<>();
// 循环数组把集群节点添加到set集合中
for (String node : sentinels) {
//添加节点
nodes.add(node);
}
if(StringUtils.isNotBlank(redisProperties.getSentinel().getPassword())){
return new JedisSentinelPool(redisProperties.getSentinel().getMaster(),nodes,jedisPoolConfig, redisProperties.getTimeout(),redisProperties.getTimeout(),
redisProperties.getPassword(),redisProperties.getDatabase(),null,redisProperties.getTimeout(),redisProperties.getTimeout(),
redisProperties.getSentinel().getPassword(),null);
}else{
return new JedisSentinelPool(redisProperties.getSentinel().getMaster(),nodes,jedisPoolConfig,redisProperties.getTimeout(),redisProperties.getPassword() );
}
}
@ConditionalOnProperty(value = "redis.model",havingValue = "cluster",matchIfMissing = false)
@Bean
public JedisCluster getJedisCluster() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(jedisProperties.getMaxIdle());
poolConfig.setMaxWaitMillis(jedisProperties.getMaxWait());
poolConfig.setMinIdle(jedisProperties.getMinIdle());
poolConfig.setMaxTotal(jedisProperties.getMaxActive());
// 截取集群节点
String[] cluster = redisProperties.getCluster().getNodes().toArray(new String[0]);
// 创建set集合
Set<HostAndPort> nodes = new HashSet<>();
// 循环数组把集群节点添加到set集合中
for (String node : cluster) {
String[] host = node.split(":");
//添加集群节点
nodes.add(new HostAndPort(host[0], Integer.parseInt(host[1])));
}
//需要密码连接的创建对象方式
return new JedisCluster(nodes, redisProperties.getTimeout(), 2000, redisProperties.getCluster().getMaxRedirects(), redisProperties.getPassword(), poolConfig);
}
}
定义对业务使用的RedisManager接口
业务上使用时通过RedisManager注入进行使用,三种模式只会注入一个进去。代码如下:
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import com.fibo.ddp.common.utils.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;
import java.util.*;
public interface RedisManager {
byte[] get(byte[] key);
String get(String key);
byte[] set(byte[] key, byte[] value);
String set(String key, String value);
byte[] set(byte[] key, byte[] value, int expire);
String set(String key, String value, int expire);
void del(byte[] key);
void del(String key);
}
RedisManage的集群模式实现
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;
import java.util.*;
/**
* @author lisw
* @program ddp-project
* @description Redis管理器 集群模式
* @createDate 2022-11-01 17:19:29
**/
@Component
@ConditionalOnProperty(value = "redis.model",havingValue = "cluster",matchIfMissing = false)
@Slf4j
public class RedisManagerJedisCluster implements RedisManager{
private int expire = 0;
@Autowired(required = false)
private JedisCluster jedisCluster;
@Override
public byte[] get(byte[] key) {
return jedisCluster.get(key);
}
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public byte[] set(byte[] key, byte[] value) {
jedisCluster.set(key,value);
if(this.expire!=0){
jedisCluster.expire(key,expire);
}
return value;
}
@Override
public String set(String key, String value) {
jedisCluster.set(key,value);
if(this.expire!=0){
jedisCluster.expire(key,expire);
}
return value;
}
@Override
public byte[] set(byte[] key, byte[] value, int expire) {
jedisCluster.set(key,value);
if(expire!=0){
jedisCluster.expire(key,expire);
}
return value;
}
@Override
public String set(String key, String value, int expire) {
jedisCluster.set(key,value);
if(expire!=0){
jedisCluster.expire(key,expire);
}
return value;
}
@Override
public void del(byte[] key) {
jedisCluster.del(key);
}
@Override
public void del(String key) {
jedisCluster.del(key);
}
}
RedisManager的哨兵模式实现
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;
import java.util.*;
/**
* @author lisw
* @program ddp-project
* @description Redis管理,哨兵模式实现
* @createDate 2022-11-02 18:01:03
**/
@Component
@ConditionalOnProperty(value = "redis.model",havingValue = "sentinel",matchIfMissing = false)
@Slf4j
public class RedisManagerJedisSentinel implements RedisManager{
private int expire = 0;
@Autowired(required = false)
private JedisSentinelPool jedisPool;
@Override
public byte[] get(byte[] key) {
byte[] value = null;
Jedis jedis =null;
try {
jedis = jedisPool.getResource();
value = jedis.get(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
jedis.close();
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public String get(String key) {
String value = null;
Jedis jedis = jedisPool.getResource();
try {
value = jedis.get(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public byte[] set(byte[] key, byte[] value) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (this.expire != 0) {
jedis.expire(key, this.expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (this.expire != 0) {
jedis.expire(key, this.expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public byte[] set(byte[] key, byte[] value, int expire) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set(key, value);
if (expire != 0) {
jedis.expire(key, expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public String set(String key, String value, int expire) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (expire != 0) {
jedis.expire(key, expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public void del(byte[] key) {
Jedis jedis = jedisPool.getResource();
try {
jedis.del(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}
@Override
public void del(String key) {
Jedis jedis = jedisPool.getResource();
try {
jedis.del(key);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
RedisManager的单机模式实现
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.ParserConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;
import java.util.*;
/**
* @author lisw
* @program ddp-project
* @description Redis管理,单机模式实现
* @createDate 2022-11-01 17:09:01
**/
@Component
@ConditionalOnProperty(value = "redis.model",havingValue = "standalone",matchIfMissing = true)
@Slf4j
public class RedisManagerJedisStandalone implements RedisManager {
private int expire = 0;
@Autowired(required = false)
private JedisPool jedisPool;
@Override
public byte[] get(byte[] key) {
byte[] value = null;
Jedis jedis =null;
try {
jedis = jedisPool.getResource();
value = jedis.get(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
jedis.close();
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public String get(String key) {
String value = null;
Jedis jedis = jedisPool.getResource();
try {
value = jedis.get(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public byte[] set(byte[] key, byte[] value) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (this.expire != 0) {
jedis.expire(key, this.expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (this.expire != 0) {
jedis.expire(key, this.expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public byte[] set(byte[] key, byte[] value, int expire) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set(key, value);
if (expire != 0) {
jedis.expire(key, expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public String set(String key, String value, int expire) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (expire != 0) {
jedis.expire(key, expire);
}
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
return value;
}
@Override
public void del(byte[] key) {
Jedis jedis = jedisPool.getResource();
try {
jedis.del(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}
@Override
public void del(String key) {
Jedis jedis = jedisPool.getResource();
try {
jedis.del(key);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
业务代码注入RedisManager即可使用对应实现
@Autowired
private RedisManager redisManager;
3切换配置说明
只需修改配置文件中的redis.model配置值就可以切换redis三种模式,值分别是:standalone(单机),cluster(集群),sentinel(哨兵)
回复【30G】,获取30G容量的Java全方位视频课程资料
回复【面试冲刺】,获取5G容量的Java全方位面试资料
回复【java规范】,获取阿里巴巴Java开发规范手册
回复【插件】,获得开发效率提高10倍的Chrome插件
回复【算法】,获得Java全方位全体系算法视频可能
原文始发于微信公众号(走进Java):从单机到集群,SpringBoot集成Redis让你的架构更强大
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/107969.html