目录
简介
pom引入
yml
方法
自定义codec
工具类
简介
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它提供了一系列的分布式的Java常用对象,和许多分布式服务。
特点:
- 支持 Redis 单节点(single)模式、哨兵(sentinel)模式、主从(Master/Slave)模式以及集群(Redis Cluster)模式
- RMap中有一个功能是可以设置键值对的过期时间的,并可以注册键值对的事件监听器,但非实时性
- 由Redisson默认的编码器为JsonJacksonCodec,JsonJackson在序列化有双向引用的对象时,会出现无限循环异常
- 所以不用redission其他自带的二进制编码器,自行实现编码器(相互注入,用fastjson能 正常序列化到redis,而JsonJackson则抛出无限循环异常)
- Redisson对订阅发布的封装是RTopic,在事件发布后,订阅方需要延时一下才能收到事件。
- Redisson底层采用的是Netty 框架。支持Redis 2.8以上版本,支持Java1.6+以上版本
pom引入
<!--redis依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.15.0</version>
</dependency>
yml
spring:
redis:
database: 0 # Redis数据库索引(默认为0)
port: 6379 # Redis服务器连接端口
password: 123456 # Redis服务器连接密码(默认为空)
jedis:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
timeout: 3000ms # 连接超时时间(毫秒)
host: aliyuncs.com # Redis服务器地址(单点配置)
#sentinel: # 集群配置
#master: master1
#nodes: 172.16.33.216:16001,172.16.33.216:16002
方法
RLock rLock = redisson.getLock(KEY);
// 最常见的使用方法
rLock.lock();
// 最长等待时间waitTime,最长持有锁的时间 holdTime, 第三个是单位
rLock.tryLock(20, 15, TimeUnit.SECONDS)
// 500s 后自动释放锁
rLock.lock(500, TimeUnit.SECONDS);
// 释放锁
rLock.unlock();
// 异步执行
RLock lock = redisson.getLock("anyLock");
lock.lockAsync();
lock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);
// 分布式可重入公平锁(可异步执行,同上)
RLock fairLock = redisson.getFairLock("anyLock");
// 最常见的使用方法
fairLock.lock();
// 联锁
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 所有的锁都上锁成功才算成功。
lock.lock();
...
lock.unlock();
// 读写锁,分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常见的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();
自定义codec
Redisson提供的几种数据序列化对象编码应用:https://github.com/redisson/redisson/wiki/4.-%E6%95%B0%E6%8D%AE%E5%BA%8F%E5%88%97%E5%8C%96
想自定义codec,需要自己初始化redissonClient,再调用Redisson.create(config),而通过 redissonClient.getConfig().setCodec(...)是无效的
config.setCodec(new FastJsonCodec()); redisson = Redisson.create(config);
FastJsonCodec.java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import org.redisson.client.codec.BaseCodec;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import org.redisson.client.protocol.Decoder;
import org.redisson.client.protocol.Encoder;
import java.io.IOException;
/**
* @Author: s
* @Date: 2021/4/20 22:32
*/
public class FastJsonCodec extends BaseCodec {
private final Encoder encoder = in -> {
ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
try {
ByteBufOutputStream os = new ByteBufOutputStream(out);
JSON.writeJSONString(os, in, SerializerFeature.WriteClassName);
return os.buffer();
} catch (IOException e) {
out.release();
throw e;
} catch (Exception e) {
out.release();
throw new IOException(e);
}
};
private final Decoder<Object> decoder = (buf, state) -> JSON.parseObject(new ByteBufInputStream(buf), Object.class);
@Override
public Decoder<Object> getValueDecoder() {
return decoder;
}
@Override
public Encoder getValueEncoder() {
return encoder;
}
}
工具类
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RMapCache;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @author
* @version
*/
@Configuration
public class RedissonCache {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 默认缓存时间
*/
private static final Long DEFAULT_EXPIRED = 5 * 60L;
/**
* redis key前缀
*/
private static final String REDIS_KEY_PREFIX = "";
/**
* redisson client对象
*/
private RedissonClient redisson;
/**
* redis host
*/
@Value("${spring.redis.host}")
private String host;
/**
* redis password
*/
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private Integer port;
/**
* 连接超时时间
*/
private Integer connectTimeout = 3000;
/**
* 初始化连接
*
* @throws IOException
*/
@PostConstruct
public void init() throws IOException {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://"+ host+":"+port)
.setPassword(password)
.setDatabase(0)
.setPingTimeout(3000)
.setTimeout(5000)
.setSubscriptionConnectionMinimumIdleSize(1)
.setSubscriptionConnectionPoolSize(256)
.setConnectTimeout(connectTimeout)
.setConnectionPoolSize(256)
.setConnectionMinimumIdleSize(1)
.setRetryAttempts(3)
.setRetryInterval(3000)
.setIdleConnectionTimeout(30000)
.setClientName("com.meiguang.mgframework.extend.redis.RedisCache");
if (redisson == null) {
redisson = Redisson.create(config);
logger.info( "redis连接成功,server={}", host);
} else {
logger.warn("redis 重复连接,config={}", config);
}
}
/**
* 读取缓存
*
* @param key 缓存key
* @param <T>
* @return 缓存返回值
*/
public <T> T get(String key) {
RBucket<T> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key);
return bucket.get();
}
/**
* 以string的方式读取缓存
*
* @param key 缓存key
* @return 缓存返回值
*/
public String getString(String key) {
RBucket<String> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key, StringCodec.INSTANCE);
return bucket.get();
}
/**
* 设置缓存(注:redisson会自动选择序列化反序列化方式)
*
* @param key 缓存key
* @param value 缓存值
* @param <T>
*/
public <T> void put(String key, T value) {
RBucket<T> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key);
bucket.set(value, DEFAULT_EXPIRED, TimeUnit.SECONDS);
}
/**
* 以string的方式设置缓存
*
* @param key
* @param value
*/
public void putString(String key, String value) {
RBucket<String> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key, StringCodec.INSTANCE);
bucket.set(value, DEFAULT_EXPIRED, TimeUnit.SECONDS);
}
/**
* 以string的方式保存缓存(与其他应用共用redis时需要使用该函数)
*
* @param key 缓存key
* @param value 缓存值
* @param expired 缓存过期时间
*/
public void putString(String key, String value, long expired) {
RBucket<String> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key, StringCodec.INSTANCE);
bucket.set(value, expired <= 0 ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
}
/**
* 如果不存在则写入缓存(string方式,不带有redisson的格式信息)
*
* @param key 缓存key
* @param value 缓存值
* @param expired 缓存过期时间
*/
public boolean putStringIfAbsent(String key, String value, long expired) {
RBucket<String> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key, StringCodec.INSTANCE);
return bucket.trySet(value, expired <= 0 ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
}
/**
* 如果不存在则写入缓存(string方式,不带有redisson的格式信息)(不带过期时间,永久保存)
*
* @param key 缓存key
* @param value 缓存值
*/
public boolean putStringIfAbsent(String key, String value) {
RBucket<String> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key, StringCodec.INSTANCE);
return bucket.trySet(value);
}
/**
* 设置缓存
*
* @param key 缓存key
* @param value 缓存值
* @param expired 缓存过期时间
* @param <T> 类型
*/
public <T> void put(String key, T value, long expired) {
RBucket<T> bucket = redisson.getBucket(REDIS_KEY_PREFIX + key);
bucket.set(value, expired <= 0 ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
}
/**
* 移除缓存
*
* @param key
*/
public void remove(String key) {
redisson.getBucket(REDIS_KEY_PREFIX + key).delete();
}
/**
* 判断缓存是否存在
*
* @param key
* @return
*/
public boolean exists(String key) {
return redisson.getBucket(REDIS_KEY_PREFIX + key).isExists();
}
/**
* 暴露redisson的RList对象
*
* @param key
* @param <T>
* @return
*/
public <T> RList<T> getRedisList(String key) {
return redisson.getList(REDIS_KEY_PREFIX + key);
}
/**
* 暴露redisson的RMapCache对象
*
* @param key
* @param <K>
* @param <V>
* @return
*/
public <K, V> RMapCache<K, V> getRedisMap(String key) {
return redisson.getMapCache(REDIS_KEY_PREFIX + key);
}
/**
* 暴露redisson的RSET对象
*
* @param key
* @param <T>
* @return
*/
public <T> RSet<T> getRedisSet(String key) {
return redisson.getSet(REDIS_KEY_PREFIX + key);
}
/**
* 暴露redisson的RScoredSortedSet对象
*
* @param key
* @param <T>
* @return
*/
public <T> RScoredSortedSet<T> getRedisScoredSortedSet(String key) {
return redisson.getScoredSortedSet(REDIS_KEY_PREFIX + key);
}
/**
* 暴露redisson的Lock对象
*
* @param key
* @return
*/
public RLock getRedisLock(String key) {
return redisson.getLock(REDIS_KEY_PREFIX + key);
}
@PreDestroy
public void close() {
try {
if (redisson != null) {
redisson.shutdown();
}
} catch (Exception ex) {
logger.error( ex.getMessage(), ex);
}
}
/**
* Setter method for property <tt>host</tt>.
*
* @param host value to be assigned to property host
*/
public void setHost(String host) {
this.host = host;
}
/**
* Setter method for property <tt>password</tt>.
*
* @param password value to be assigned to property password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Setter method for property <tt>connectTimeout</tt>.
*
* @param connectTimeout value to be assigned to property connectTimeout
*/
public void setConnectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
}
}
额外功能:https://github.com/redisson/redisson/wiki/10.-%E9%A2%9D%E5%A4%96%E5%8A%9F%E8%83%BD
包括对Redis节点的操作(连接或断开),命令的批量执行以及配置事务属性