目录
[(3) application-prod.properties](#(3) application-prod.properties)
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.15.5</version>
</dependency>
<!--
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.5</version>
</dependency>
-->
支持Redis多种连接模式,这里以RedissonClient工具为例
一、Redis单例模式
#单机模式
#Redis url should start with redis:// or rediss:// (for SSL connection)
my.redisson.address = redis://127.0.0.1:6379
my.redisson.password = wtyy
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissionConfig {
@Value("${my.redisson.address}")
private String address;
@Value("${my.redisson.password}")
private String password;
/**
* 所有对Redisson的使用都是通过RedissonClient对象
*/
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(){
// 创建配置 指定redis地址及节点信息
Config config = new Config();
config.useSingleServer().setAddress(address);
//.setPassword(password);
// 根据config创建出RedissonClient实例
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
二、Redis哨兵模式
my.redisson.sentinel.schema=
my.redisson.sentinel.address = redis://xxx.xx.xxx1:19601,redis://xxx.xx.xxx2:19601,redis://xxx.xx.xxx3:19601
my.redisson.sentinel.password = N5WAXX4z9qw
my.redisson.sentinel.master = master-test
my.redisson.sentinel.database = 10
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissionConfig {
@Value("${my.redisson.sentinel.address}")
private String address;
@Value("${my.redisson.sentinel.password}")
private String password;
@Value("${my.redisson.sentinel.master}")
private String master;
@Value("${my.redisson.sentinel.database}")
private Integer dataBase;
@Value("${my.redisson.sentinel.schema}")
private String schema;
/**
* 所有对Redisson的使用都是通过RedissonClient对象
*/
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(){
Config config = new Config();
config.useSentinelServers()
.setScanInterval(2000) // cluster state scan interval in milliseconds
.addSentinelAddress(address.split(","))
.setCheckSentinelsList(false)
.setMasterName(master)
.setPassword(password)
.setDatabase(dataBase);
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
三、Redis集群模式
Config config = new Config();
config.useClusterServers()
.setScanInterval(2000) // cluster state scan interval in milliseconds
.addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001")
.addNodeAddress("redis://127.0.0.1:7002");
RedissonClient redisson = Redisson.create(config);
四、主从模式
Config config = new Config();
config.useMasterSlaveServers()
.setMasterAddress("redis://127.0.0.1:6379")
.addSlaveAddress("redis://127.0.0.1:6389", "redis://127.0.0.1:6332", "redis://127.0.0.1:6419")
.addSlaveAddress("redis://127.0.0.1:6399");
RedissonClient redisson = Redisson.create(config);
五、兼容多种模式的配置(重点)
从上面可以看到,不同的redis模式有不同的连接配置方式,如果连接变更,配置代码也要跟着变更,不够灵活,再比如有多套环境,测试环境和生产环境使用的是不同的redis模式,所以需要考虑配置兼容问题。下面的配置适用于所有模式。
1、pom
因为使用到了 RedisProperties,所以需要引入 spring-boot-starter-data-redis
<?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="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>redis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.4</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.26.0</version>
</dependency>
<!--连接池依赖-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--hutool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
</project>
2、配置文件
按照 org.springframework.boot.autoconfigure.data.redis.RedisProperties 规则配置。源码:
package org.springframework.boot.autoconfigure.data.redis;
@ConfigurationProperties(
prefix = "spring.data.redis"
)
public class RedisProperties {
private int database = 0;
private String url;
private String host = "localhost";
private String username;
private String password;
private int port = 6379;
private Duration timeout;
private Duration connectTimeout;
private String clientName;
private ClientType clientType;
private Sentinel sentinel;
private Cluster cluster;
private final Ssl ssl = new Ssl();
private final Jedis jedis = new Jedis();
private final Lettuce lettuce = new Lettuce();
......
}
这里有两套环境:dev和prod
(1)application.properties
spring.profiles.active=dev
(2)application-dev.properties
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.password=
spring.data.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1
spring.data.redis.lettuce.pool.max-idle=8
spring.data.redis.lettuce.pool.min-idle=0
spring.data.redis.lettuce.pool.enabled=true
spring.data.redis.lettuce.pool.time-between-eviction-runs=30s
(3) application-prod.properties
spring.data.redis.cluster.nodes=xxx.xxx.xx.xxx:6379
spring.data.redis.cluster.max-redirects=3
spring.data.redis.timeout=60S
spring.data.redis.lettuce.pool.max-wait=2S
spring.data.redis.lettuce.pool.max-active=1200
spring.data.redis.lettuce.pool.max-idle=400
spring.data.redis.lettuce.pool.min-idle=50
# spring.redis.lettuce.pool.time-between-eviction-runs=200
spring.data.redis.lettuce.pool.enabled=true
spring.data.redis.lettuce.pool.time-between-eviction-runs=30s
spring.data.redis.lettuce.cluster.refresh.adaptive=true
spring.data.redis.lettuce.cluster.refresh.period=60s
3、Java配置类
读取配置文件中 spring.data.redis 开头的配置,并加以判断。
package org.example.config;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Configuration
public class RedissonConfig {
@Autowired
RedisProperties redisProperties;
private static final String REDIS_PROTOCOL_PREFIX = "redis://";
private static final String REDISS_PROTOCOL_PREFIX = "rediss://";
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() {
Config config;
Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties);
int timeout;
if (null == timeoutValue) {
timeout = 10000;
} else if (!(timeoutValue instanceof Integer)) {
Method millisMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
timeout = ((Long) ReflectionUtils.invokeMethod(millisMethod, timeoutValue)).intValue();
} else {
timeout = (Integer) timeoutValue;
}
if (redisProperties.getSentinel() != null) {
Method nodesMethod =
ReflectionUtils.findMethod(RedisProperties.Sentinel.class, "getNodes");
Object nodesValue =
ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel());
String[] nodes;
if (nodesValue instanceof String) {
nodes = convert(Arrays.asList(((String) nodesValue).split(",")));
} else {
nodes = convert((List<String>) nodesValue);
}
config = new Config();
config.useSentinelServers()
.setMasterName(redisProperties.getSentinel().getMaster())
.addSentinelAddress(nodes)
.setDatabase(redisProperties.getDatabase())
.setConnectTimeout(timeout)
.setPassword(redisProperties.getPassword());
} else if (clusterMethod != null
&& ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) {
Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, redisProperties);
Method nodesMethod = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
List<String> nodesObject =
(List) ReflectionUtils.invokeMethod(nodesMethod, clusterObject);
String[] nodes = convert(nodesObject);
config = new Config();
config.useClusterServers()
.addNodeAddress(nodes)
.setConnectTimeout(timeout)
.setPassword(redisProperties.getPassword());
} else {
config = new Config();
String prefix = REDIS_PROTOCOL_PREFIX;
Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
if (method != null && (Boolean) ReflectionUtils.invokeMethod(method, redisProperties)) {
prefix = REDISS_PROTOCOL_PREFIX;
}
String password =
StringUtils.isBlank(redisProperties.getPassword())
? null
: redisProperties.getPassword();
config.useSingleServer()
.setAddress(
prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
.setConnectTimeout(timeout)
.setDatabase(redisProperties.getDatabase())
.setPassword(password);
}
return Redisson.create(config);
}
private String[] convert(List<String> nodesObject) {
List<String> nodes = new ArrayList<String>(nodesObject.size());
for (String node : nodesObject) {
if (!node.startsWith(REDIS_PROTOCOL_PREFIX)
&& !node.startsWith(REDISS_PROTOCOL_PREFIX)) {
nodes.add(REDIS_PROTOCOL_PREFIX + node);
} else {
nodes.add(node);
}
}
return nodes.toArray(new String[nodes.size()]);
}
}
这里用了反射,其实RedisProperties对象已经拿到了,直接从 redisProperties中get也是可以的:
RedisProperties.Cluster cluster = redisProperties.getCluster();
4、应用
import com.alibaba.fastjson.JSON;
import org.example.dto.UserDTO;
import org.example.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = {Main.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class RedissonTest {
@Autowired
private RedissonClient redissonClient;
@Test
public void testString(){
RBucket<Object> bucket = redissonClient.getBucket("test");
bucket.set("这是value");
System.out.println(bucket.get());
}
}
5、与RedisTemplate并存使用
这个demo引入了 spring-boot-starter-data-redis,所以可以直接使用RedisTemplate:
@SpringBootTest(classes = {Main.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class MyTest {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private UserService userService;
@Test
public void testString(){
String key = "string-name";
//存
String value = "这是value123";
stringRedisTemplate.opsForValue().set(key,value);
//取
Object valueObj = stringRedisTemplate.opsForValue().get(key);
System.out.println("value为:" + valueObj);
}
}