springboot之如何同時連接多個redis
線上服務(wù)需要連接三個redis服務(wù)器;業(yè)務(wù)背景不能介紹,直接上代碼:
技術(shù)選型
Springboot連接reids的三個客戶端
Jedis:是Redis的Java實現(xiàn)客戶端,提供了比較全面的Redis命令的支持,復(fù)雜的redis操作需要使用它;springboot1.x 默認(rèn)集成;據(jù)說在高并發(fā)下有并發(fā)性問題出現(xiàn);
Lettuce:高級Redis客戶端,用于線程安全同步,異步和響應(yīng)使用,支持集群,Sentinel,管道和編碼器,springboot 2.x 默認(rèn)集成
Redission:Redisson是一個在Redis的基礎(chǔ)上實現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務(wù)。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進(jìn)使用者對Redis的關(guān)注分離(Separation of Concern),從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務(wù)邏輯上。暫時企業(yè)級開發(fā)感覺只是使用了分布式鎖;
結(jié)論:
單個redis隨便使用哪個客戶端都可以,也可以使用 Jedis + Redission 或者 Lettuce + Redission;
由于Jedis使用和研究比較多,此處使用Jedis拋磚引玉,實現(xiàn)三組redis + 分布式鎖;Lettuce版本也可以根據(jù)此思路編寫;
代碼部分
maven pom引用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <!-- 不依賴Redis的異步客戶端lettuce --> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
application.yml配置
spring:
redis:
r1:
host: 192.168.1.210
port: 6379
password:
#cluster:
#nodes: 192.168.1.101:6379,192.168.1.102:6379,192.168.1.103:6379
r2:
host: 192.168.1.211
port: 6379
password:
#cluster:
#nodes: 192.168.1.104:6379,192.168.1.105:6379,192.168.1.106:6379
r3:
host: 192.168.1.212
port: 6379
password:
#cluster:
#nodes: 192.168.1.107:6379,192.168.1.108:6379,192.168.1.109:6379Configuration代碼
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.JedisPoolConfig;
/**
* redis配置 三個redis同時存在
* @author douzi
* @date 2021-12-2 09:00:00
*/
@Slf4j
@Configuration
public class RedisJedisConfig2 {
// r1 redis 配置信息
@Value("${spring.redis.r1.host:}")
private String r1Host;
@Value("${spring.redis.r1.port:}")
private Integer r1Port;
@Value("${spring.redis.r1.password:}")
private String r1Password;
@Value("${spring.redis.r1.cluster.nodes:}")
private String r1Nodes;
//r2 redis 配置信息
@Value("${spring.redis.r2.host:}")
private String r2Host;
@Value("${spring.redis.r2.port:}")
private Integer r2Port;
@Value("${spring.redis.r2.password:}")
private String r2Password;
@Value("${spring.redis.r2.cluster.nodes:}")
private String r2Nodes;
//r3 redis 配置信息
@Value("${spring.redis.r3.host:}")
private String r3Host;
@Value("${spring.redis.r3.port:}")
private Integer r3Port;
@Value("${spring.redis.r3.password:}")
private String r3Password;
@Value("${spring.redis.r3.cluster.nodes:}")
private String r3Nodes;
/**
* connectionFactory 配置工廠
*/
public RedisConnectionFactory connectionFactory(
RedisStandaloneConfiguration redisStandaloneConfiguration,
RedisClusterConfiguration redisClusterConfiguration,
JedisPoolConfig jedisPoolConfig) {
if (redisStandaloneConfiguration == null && redisClusterConfiguration == null) {
log.error("==============請?zhí)砑觬edis配置================");
return null;
}
JedisConnectionFactory jedisConnectionFactory = null;
if (redisStandaloneConfiguration != null) {
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
} else {
jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
}
jedisConnectionFactory.afterPropertiesSet();
// 檢查是否可用
RedisConnection connection = null;
try {
connection = jedisConnectionFactory.getConnection();
log.info("reids是否可用:" + !connection.isClosed());
} catch(Exception e) {
log.error("reids不可用,請檢查組件是否啟動:",e);
} finally {
connection.close();
}
return jedisConnectionFactory;
}
/**
* poolConfig連接池配置 只有集群時使用 直接寫死,不讓外部配置了
* @return
*/
public JedisPoolConfig poolConfig() {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(200);
config.setMaxIdle(50);
config.setMinIdle(8);
config.setMaxWaitMillis(10000); // 獲取連接時的最大等待毫秒數(shù)(如果設(shè)置為阻塞時BlockWhenExhausted),如果超時就拋異常, 小于零:阻塞不確定的時間, 默認(rèn)-1
config.setTestOnBorrow(true); // 在獲取連接的時候檢查有效性, 默認(rèn)false
config.setTestOnReturn(false); // 調(diào)用returnObject方法時,是否進(jìn)行有效檢查
config.setTestWhileIdle(true); // Idle時進(jìn)行連接掃描
config.setTimeBetweenEvictionRunsMillis(30000); // 表示idle object evitor兩次掃描之間要sleep的毫秒數(shù)
config.setNumTestsPerEvictionRun(10); // 表示idle object evitor每次掃描的最多的對象數(shù)
config.setMinEvictableIdleTimeMillis(60000); // 表示一個對象至少停留在idle狀態(tài)的最短時間,然后才能被idle object evitor掃描并驅(qū)逐;這一項只有在timeBetweenEvictionRunsMillis大于0時才有意義
return config;
}
/**
* redisStandaloneConfiguration 單機(jī)版配置
* @param host
* @param port
* @param password
* @param index
* @return
*/
public RedisStandaloneConfiguration redisStandaloneConfiguration(String host, int port, String password, int index) {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host, port);
if (StrUtil.isNotBlank(password)) {
redisStandaloneConfiguration.setPassword(password);
}
if (index != 0) {
redisStandaloneConfiguration.setDatabase(index);
}
return redisStandaloneConfiguration;
}
/**
* redisClusterConfiguration 集群配置
* @param clusterNodes
* @param password
* @return
*/
public RedisClusterConfiguration redisClusterConfiguration(String clusterNodes, String password) {
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
// Set<RedisNode> clusterNodes
String[] serverArray = clusterNodes.split(",");
Set<RedisNode> nodes = new HashSet<RedisNode>();
for (String ipPort : serverArray) {
String[] ipAndPort = ipPort.split(":");
nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
}
redisClusterConfiguration.setClusterNodes(nodes);
redisClusterConfiguration.setMaxRedirects(6);
if (StrUtil.isNotBlank(password)) {
redisClusterConfiguration.setPassword(RedisPassword.of(password));
}
return redisClusterConfiguration;
}
@Bean(name = "redisR1Template")
public RedisTemplate<String, Object> redisR1Template() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisStandaloneConfiguration redisStandaloneConfiguration = null;
RedisClusterConfiguration redisClusterConfiguration = null;
if (StrUtil.isNotBlank(r1Host) && StrUtil.isBlank(r1Nodes)) {
redisStandaloneConfiguration = redisStandaloneConfiguration(r1Host, r1Port, r1Password, 0);
} else if (StrUtil.isNotBlank(r1Nodes)) {
redisClusterConfiguration = redisClusterConfiguration(r1Nodes, r1Password);
}
log.info("=========================R1 redis信息 開始===============================");
template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig()));
log.info("=========================R1 redis信息 結(jié)束===============================");
return template;
}
@Bean(name = "redisR2Template")
public RedisTemplate<String, Object> redisR2Template() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisStandaloneConfiguration redisStandaloneConfiguration = null;
RedisClusterConfiguration redisClusterConfiguration = null;
if (StrUtil.isNotBlank(r2Host) && StrUtil.isBlank(r2Nodes)) {
redisStandaloneConfiguration = redisStandaloneConfiguration(r2Host, r2Port, r2Password, 0);
} else if (StrUtil.isNotBlank(r2Nodes)) {
redisClusterConfiguration = redisClusterConfiguration(r2Nodes, r2Password);
}
log.info("=========================R2 redis信息 開始===============================");
template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig()));
log.info("=========================R2 redis信息 結(jié)束===============================");
return template;
}
@Bean(name = "redisR3Template")
public RedisTemplate<String, Object> redisR3Template() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisStandaloneConfiguration redisStandaloneConfiguration = null;
RedisClusterConfiguration redisClusterConfiguration = null;
if (StrUtil.isNotBlank(r3Host) && StrUtil.isBlank(r3Nodes)) {
redisStandaloneConfiguration = redisStandaloneConfiguration(r3Host, r3Port, r3Password, 0);
} else if (StrUtil.isNotBlank(r3Nodes)) {
redisClusterConfiguration = redisClusterConfiguration(r3Nodes, r3Password);
}
log.info("=========================R3 redis信息 開始===============================");
template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig()));
log.info("=========================R3 redis信息 結(jié)束===============================");
return template;
}
}其中在connectionFactory方法中,添加了,自動檢查redis是否連接成功的代碼,在啟動項目時即可判斷是否連接成功。
啟動失敗日志

啟動成功日志

類中使用
@RestController
@RequestMapping("/redis")
public class TestRedisController {
@Autowired
RedisTemplate<String, Object> redisR1Template;
@Autowired
RedisTemplate<String, Object> redisR2Template;
@Autowired
RedisTemplate<String, Object> redisR3Template;
@GetMapping("/cs")
public String test() {
redisR1Template.opsForValue().get("1");
redisR2Template.opsForValue().get("1");
redisR3Template.opsForValue().get("1");
return "1";
}
}總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
如何使用Java redis實現(xiàn)發(fā)送手機(jī)驗證碼功能
這篇文章主要介紹了如何使用Java redis實現(xiàn)發(fā)送手機(jī)驗證碼功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-05-05
認(rèn)識Java底層操作系統(tǒng)與并發(fā)基礎(chǔ)
這篇文章主要介紹了認(rèn)識Java底層操作系統(tǒng)與并發(fā)基礎(chǔ),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-07-07
Java序列化和反序列化_動力節(jié)點Java學(xué)院整理
把對象轉(zhuǎn)換為字節(jié)序列的過程稱為對象的序列化,把字節(jié)序列恢復(fù)為對象的過程稱為對象的反序列化。接下來通過本文給大家介紹Java序列化和反序列化及主要的兩種用途,感興趣的的友參考下吧2017-05-05
Java無需解壓直接讀取ZIP壓縮包里的文件及內(nèi)容
最近開發(fā)的時候遇到要獲取到zip壓縮包里面的文件內(nèi)容,解決方案就是通過ZipInputStream來讀取,下面通過實例代碼介紹Java無需解壓直接讀取ZIP壓縮包里的文件及內(nèi)容,感興趣的朋友跟隨小編一起看看吧2024-03-03
Spring+Quartz實現(xiàn)動態(tài)任務(wù)調(diào)度詳解
這篇文章主要介紹了Spring+Quartz實現(xiàn)動態(tài)任務(wù)調(diào)度詳解,最近經(jīng)?;趕pring?boot寫定時任務(wù),并且是使用注解的方式進(jìn)行實現(xiàn),分成的方便將自己的類注入spring容器,需要的朋友可以參考下2024-01-01

