Redisson是一款基于java开发的开源项目,提供了很多企业级实践,比如分布式锁、消息队列、异步执行等功能。本文基于Springboot2版本集成redisson-spring-boot-starter实现redisson的基本应用
软件环境:
-
JDK 1.8
-
SpringBoot 2.2.1
-
Maven 3.2+
-
Mysql 8.0.26
-
redisson-spring-boot-starter 3.15.6
-
开发工具
-
IntelliJ IDEA
-
smartGit
-
项目搭建:
快速新建一个Spring Initializr项目,service url
就选择这个https://start.aliyun.com
,spring官网的url
选择jdk的版本,maven类型的项目
选择需要的依赖,选择之后,新生成的项目就会自动加上需要的maven配置,点击next生成一个SpringBoot的项目,不需要自己手工进行配置maven
这个里面没集成Redisson的starter,所以需要手工进行配置,需要注意一下redisson-spring-boot-starter
和SpringBoot
对应的版本关系
pom.xml
文件加上redisson-spring-boot-starter
配置,然后reimport
引入jar
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.6</version>
</dependency>
对于Redisson的配置,有多种方式,可以使用json文件配置,也可以使用yaml文件配置,然后再引进来,如下,新建一个redisson.yml
文件,加上单机版的配置
redisson.yml
singleServerConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
password: null
subscriptionsPerConnection: 5
clientName: null
address: "redis://127.0.0.1:6379"
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 32
connectionPoolSize: 64
database: 0
dnsMonitoringInterval: 5000
threads: 8
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
"transportMode":"NIO"
在application.yml
里引进redisson.yml
spring:
redis:
redisson:
file: classpath:redisson.yml
另外一种方式是可以直接在application.yml
里直接加上配置,这种方式可能对于使用了分布式配置中心管理的项目更加方便一些
spring:
redis:
redisson:
config: |
singleServerConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
password: null
subscriptionsPerConnection: 5
clientName: null
address: "redis://127.0.0.1:6379"
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 32
connectionPoolSize: 64
database: 0
dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"
在项目中如果想要自己加上配置,创建一个redisson可以先创建一个Config对象,如何进行设置就可以
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.8.12
8:6379");
config.setCodec(new StringCodec());
return Redisson.create(config);
翻看redisson-spring-boot-starter的源码,也是创建Config,进行设置,这个starter为我们提供了自动配置功能,源码路径:org.redisson.spring.starter.RedissonAutoConfiguration#redisson
public RedissonClient redisson() throws IOException {
Config config = null;
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 (redissonProperties.getConfig() != null) {
try {
config = Config.fromYAML(redissonProperties.getConfig());
} catch (IOException e) {
try {
config = Config.fromJSON(redissonProperties.getConfig());
} catch (IOException e1) {
throw new IllegalArgumentException("Can't parse config", e1);
}
}
} else if (redissonProperties.getFile() != null) {
try {
InputStream is = getConfigStream();
config = Config.fromYAML(is);
} catch (IOException e) {
// trying next format
try {
InputStream is = getConfigStream();
config = Config.fromJSON(is);
} catch (IOException e1) {
throw new IllegalArgumentException("Can't parse config", e1);
}
}
} else if (redisProperties.getSentinel() != null) {
Method nodesMethod = ReflectionUtils.findMethod(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;
}
config.useSingleServer()
.setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
.setConnectTimeout(timeout)
.setDatabase(redisProperties.getDatabase())
.setPassword(redisProperties.getPassword());
}
if (redissonAutoConfigurationCustomizers != null) {
for (RedissonAutoConfigurationCustomizer customizer : redissonAutoConfigurationCustomizers) {
customizer.customize(config);
}
}
return Redisson.create(config);
}
在项目中使用的话,一般直接用@Resource
加一个RedissonClient
即可,不需要自己创建了,下面给出使用Redisson API实现的共同关注的人和排名榜的简单例子
package com.example.redission;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.redisson.api.*;
import org.redisson.client.RedisClient;
import org.redisson.client.protocol.ScoredEntry;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.IntStream;
@SpringBootTest
class SpringbootRedissionApplicationTests {
@Resource
private RedissonClient redissonClient;
@Test
void contextLoads() throws ExecutionException, InterruptedException {
// 共同关注的人
RSet<Object> tom = redissonClient.getSet("tom");
tom.addAll(Lists.newArrayList("令狐冲","james","风清扬"));
RSet<Object> jack = redissonClient.getSet("jack");
jack.addAll(Lists.newArrayList("令狐冲","tim","jack"));
System.out.println("共同关注的人:"+tom.readIntersectionAsync("jack").get());
// 排名榜
RScoredSortedSet<String> school = redissonClient.getScoredSortedSet("school");
school.add(60, "tom");
school.add(60, "jack");
school.add(60, "tim");
school.addScore("tom", 20);
school.addScore("jack", 10);
school.addScore("tim", 30);
RFuture<Collection<ScoredEntry<String>>> collectionRFuture = school.entryRangeReversedAsync(0, -1);
Iterator<ScoredEntry<String>> iterator = collectionRFuture.get().iterator();
System.out.println("成绩从高到低排序");
while(iterator.hasNext()) {
ScoredEntry<String> next = iterator.next();
String value = next.getValue();
System.out.println(value);
}
RFuture<Collection<ScoredEntry<String>>> collectionRFuture1 = school.entryRangeReversedAsync(0, 2);
Iterator<ScoredEntry<String>> iterator1 = collectionRFuture1.get().iterator();
System.out.println("成绩前三名");
while (iterator1.hasNext()) {
System.out.println(iterator1.next().getValue());
}
}
}
附录
官网的Readme文档:https://github.com/redisson/redisson/blob/master/redisson-spring-boot-starter/README.md