Skip to content

springboot集成redisson

一、简介

Redisson 是构建在 Redis 之上的 Java 客户端,常用于分布式锁、限流、延迟队列、布隆过滤器等场景。

Redisson 基于 Netty 和 Redis 的能力做了较完整的封装,在 Java 常用接口的基础上扩展出一套适用于分布式环境的工具集。相比直接操作 Redis 命令,Redisson 更适合在业务代码中以对象化方式使用分布式能力。

在加锁场景中,Redisson 默认会启用 watchdog 看门狗机制。客户端成功加锁后,看门狗线程会定时检查锁是否仍由当前线程持有,如果是,就持续延长锁的过期时间,避免业务执行过程中锁被提前释放。

默认情况下,看门狗超时时间为 30 秒,也可以通过 Config.lockWatchdogTimeout 单独配置。

lock.lock() 默认启用看门狗,而 lock.lock(timeout, timeUnit) 这类显式指定过期时间的方式不会启用看门狗。

//启用看门狗
lock.lock();
//不启用看门狗
lock.lock(timeout,timeUnit);

二、依赖

Redisson 与 Spring Boot 版本需要相互匹配,常见对应关系如下:

redisson-spring-boot-starter的3.26.1对应spring-boot的3.2.2;

redisson-spring-boot-starter的3.26.0对应spring-boot的3.2.0;

redisson-spring-boot-starter的3.18.0对应spring-boot的2.7.2;

redisson-spring-boot-starter的3.16.0对应spring-boot的2.4.4;
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.15.4</version>
</dependency>

三、配置文件

可以在 resources 目录下增加 Redisson 配置文件,下面给出常见配置示例。

spring:
  redis:
    redisson:
      config: |
        singleServerConfig:

3.1 单机配置

singleServerConfig:
  #如果一段timeout时间未使用池化连接,并且当前连接量大于最小空闲连接池大小,则它将关闭并从池中删除。值(以毫秒为单位)。默认10000
  idleConnectionTimeout: 10000
  #连接到任何Redis服务器时超时。默认10000
  connectTimeout: 10000
  #Redis服务器响应超时。成功发送Redis命令后,开始倒数计时。值(以毫秒为单位)。默认3000
  timeout: 3000
  #超时重试次数,默认3次
  retryAttempts: 3
  #重试的时间间隔,默认1500毫秒
  retryInterval: 1500
  #密码,如果没有设置null或者不设置,默认为null
  # password: null
  #每个Redis连接限制的订阅,默认5
  subscriptionsPerConnection: 5
  #客户端连接名称,默认为null
  clientName: null
  #连接地址,一定要下面这种格式。默认本机的6379端口
  address: "redis://127.0.0.1:6379"
  #最小空闲Redis订阅连接数量。默认1
  subscriptionConnectionMinimumIdleSize: 1
  #Redis订阅连接最大池大小。默认50
  subscriptionConnectionPoolSize: 50
  #最小空闲Redis连接数。默认24
  connectionMinimumIdleSize: 32
  #Redis连接的最大池大小。默认64
  connectionPoolSize: 1024
  #DNS更改监视时间间隔。应用程序必须确保JVM DNS缓存TTL足够低以支持此功能。设置-1为禁用。代理模式支持单个主机名的多个IP绑定。默认5000
  dnsMonitoringInterval: 5000
threads: 16
nettyThreads: 64
  # 默认 org.redisson.codec.MarshallingCodec,部分编码需要引入对应编码依赖
codec: !<org.redisson.codec.JsonJacksonCodec> {}
  # 传输模式默认 NIO,可选值还包括 EPOLL(Linux)和 KQUEUE(macOS)
transportMode: "NIO"

3.2 哨兵配置

sentinelServersConfig:
  #如果一段timeout时间未使用池化连接,并且当前连接量大于最小空闲连接池大小,则它将关闭并从池中删除。值(以毫秒为单位)。默认10000
  idleConnectionTimeout: 10000
  #连接到任何Redis服务器时超时。默认10000
  connectTimeout: 10000
  #Redis服务器响应超时。成功发送Redis命令后,开始倒数计时。值(以毫秒为单位)。默认3000
  timeout: 3000
  #超时重试次数,默认3次
  retryAttempts: 3
  #重试的时间间隔,默认1500毫秒
  retryInterval: 1500
  #从可用服务器的内部列表中排除的Redis Slave重新连接尝试间隔。在每个超时事件中,Redisson都会尝试连接到已断开连接的Redis服务器。值(以毫秒为单位)默认3000
  failedSlaveReconnectionInterval: 3000
  #当此服务器上第一次Redis命令执行失败的时间间隔达到定义的值时,将从可用节点的内部列表中排除无法执行命令的Redis从节点。值(以毫秒为单位)。默认60000
  failedSlaveCheckInterval: 60000
  #密码,如果没有设置null或者不设置,默认为null
  #  password: null
  #每个Redis连接限制的订阅
  subscriptionsPerConnection: 5
  #客户端名称。默认null
  # clientName: null
  # 在使用多个Redis服务节点的环境里,可以选用以下几种负载均衡方式选择一个节点:
  # org.redisson.connection.balancer.WeightedRoundRobinBalancer - 权重轮询调度算法
  # org.redisson.connection.balancer.RoundRobinLoadBalancer - 轮询调度算法
  # org.redisson.connection.balancer.RandomLoadBalancer - 随机调度算法
  # 默认:RoundRobinLoadBalancer
  loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
  # 长期保持一定数量的发布订阅连接是必须的。默认1
  subscriptionConnectionMinimumIdleSize: 1
  # 多从节点的环境里,每个从服务节点里用于发布和订阅连接的连接池最大容量。连接池的连接数量自动弹性伸缩。默认50
  subscriptionConnectionPoolSize: 50
  # 多从节点的环境里,每个从服务节点里用于普通操作(非 发布和订阅)的最小保持连接数(长连接)。
  # 长期保持一定数量的连接有利于提高瞬时读取反映速度。默认32
  slaveConnectionMinimumIdleSize: 32
  # 多从节点的环境里,每个从服务节点里用于普通操作(非 发布和订阅)连接的连接池最大容量。连接池的连接数量自动弹性伸缩。默认64
  slaveConnectionPoolSize: 512
  # 多从节点的环境里,每个主节点的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时写入反应速度。默认32
  masterConnectionMinimumIdleSize: 32
  # 多主节点的环境里,每个主节点的连接池最大容量。连接池的连接数量自动弹性伸缩。 默认64
  masterConnectionPoolSize: 512
  # 设置读取操作选择节点的模式。 可用值为:
  # SLAVE - 只在从服务节点里读取。 默认
  # MASTER - 只在主服务节点里读取。
  # MASTER_SLAVE - 在主从服务节点里都可以读取。
  readMode: "SLAVE"
  # 设置订阅操作选择节点的模式。可用值为:
  # SLAVE - 只在从服务节点里订阅。默认
  # MASTER - 只在主服务节点里订阅。
  subscriptionMode: "SLAVE"
  #服务器地址,一定要按这种格式配置
  sentinelAddresses:
    - "redis://127.0.0.1:7001"
    - "redis://127.0.0.1:7002"
  #Redis Sentinel服务器和主更改监视任务使用的主服务器名称。
  # masterName: "mymaster"
threads: 16
nettyThreads: 64
  # Redisson 提供了多种序列化编解码器,可根据业务场景选择
codec: !<org.redisson.codec.JsonJacksonCodec> {}
  # 传输模式默认 NIO,可选值还包括 EPOLL(Linux)和 KQUEUE(macOS)
transportMode: "NIO"

3.3 集群配置

clusterServersConfig:
  # 如果当前连接池里的连接数量超过了最小空闲连接数,而同时有连接空闲时间超过了该数值,
  # 那么这些连接将会自动被关闭,并从连接池里去掉。时间单位是毫秒。默认10000
  idleConnectionTimeout: 10000
  # 同节点建立连接时的等待超时。时间单位是毫秒。默认10000
  connectTimeout: 10000
  # 等待节点回复命令的时间。该时间从命令发送成功时开始计时。默认3000
  timeout: 5000
  # 命令失败重试次数,如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误。
  # 如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时。默认值3
  retryAttempts: 3
  # 在一条命令发送失败以后,等待重试发送的时间间隔。时间单位是毫秒。默认1500
  retryInterval: 1500
  # 失败从节点重连间隔时间
  failedSlaveReconnectionInterval: 1000
  # 失败从节点校验间隔时间
  failedSlaveCheckInterval: 5000
  # 用于节点身份验证的密码。默认null
  password: your-redis-password
  # 每个连接的最大订阅数量。默认5
  subscriptionsPerConnection: 5
  # 在Redis节点里显示的客户端名称。默认null
  clientName: redis-client
  # 在使用多个Redis服务节点的环境里,可以选用以下几种负载均衡方式选择一个节点:
  # org.redisson.connection.balancer.WeightedRoundRobinBalancer - 权重轮询调度算法
  # org.redisson.connection.balancer.RoundRobinLoadBalancer - 轮询调度算法
  # org.redisson.connection.balancer.RandomLoadBalancer - 随机调度算法
  # 默认:RoundRobinLoadBalancer
  loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
  # 用于发布和订阅连接的最小保持连接数(长连接)。Redisson内部经常通过发布和订阅来实现许多功能。
  # 长期保持一定数量的发布订阅连接是必须的。默认1
  subscriptionConnectionMinimumIdleSize: 1
  # 多从节点的环境里,每个从服务节点里用于发布和订阅连接的连接池最大容量。连接池的连接数量自动弹性伸缩。默认50
  subscriptionConnectionPoolSize: 50
  # 多从节点的环境里,每个从服务节点里用于普通操作(非 发布和订阅)的最小保持连接数(长连接)。
  # 长期保持一定数量的连接有利于提高瞬时读取反映速度。默认32
  slaveConnectionMinimumIdleSize: 32
  # 多从节点的环境里,每个从服务节点里用于普通操作(非 发布和订阅)连接的连接池最大容量。连接池的连接数量自动弹性伸缩。默认64
  slaveConnectionPoolSize: 1024
  # 多从节点的环境里,每个主节点的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时写入反应速度。默认32
  masterConnectionMinimumIdleSize: 32
  # 多主节点的环境里,每个主节点的连接池最大容量。连接池的连接数量自动弹性伸缩。 默认64
  masterConnectionPoolSize: 1024
  # 设置读取操作选择节点的模式。 可用值为:
  # SLAVE - 只在从服务节点里读取。 默认
  # MASTER - 只在主服务节点里读取。
  # MASTER_SLAVE - 在主从服务节点里都可以读取。
  readMode: "SLAVE"
  # 设置订阅操作选择节点的模式。可用值为:
  # SLAVE - 只在从服务节点里订阅。默认
  # MASTER - 只在主服务节点里订阅。
  subscriptionMode: "SLAVE"
  # 集群节点地址
  nodeAddresses:
    - "redis://127.0.0.1:7001"
    - "redis://127.0.0.1:7002"
    - "redis://127.0.0.1:7003"
    - "redis://127.0.0.1:7004"
    - "redis://127.0.0.1:7005"
    - "redis://127.0.0.1:7006"
  # 对主节点变化节点状态扫描的时间间隔。单位是毫秒。
  scanInterval: 1000
  # ping连接间隔。0为禁用,默认 30000,单位毫秒
  pingConnectionInterval: 30000
  # 启用TCP keepAlive进行连接,默认false
  keepAlive: false
  # 启用TCP noDelay进行连接,默认false
  tcpNoDelay: false
threads: 16
nettyThreads: 32
  # Redisson 提供了多种序列化编解码器,可根据业务场景选择
codec: !<org.redisson.codec.JsonJacksonCodec> {}
  # 传输模式默认 NIO,可选值还包括 EPOLL(Linux)和 KQUEUE(macOS)
transportMode: "NIO"

四、Redisson使用

工具类

package com.lcy.base.redis.util;

import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import com.lcy.base.common.spring.SpringApplicationContext;
import lombok.extern.slf4j.Slf4j;

/**
 * @Description 加锁工具类
 * @Author lcy
 * @Date 2021/8/20 15:07
 */
@Slf4j
public class LockUtil {

    /**
     * @Description 加锁操作类
     * @Author lcy
     * @Date 2021/8/20 15:07
     */
    public interface LockOperation {

        /**
         * 加锁以后的操作
         * @author lcy
         * @date 2021/8/20 15:08
         **/
        void lockOperation();
    }

    /**
     * 通过redis加锁操作
     * @param lockKey       锁的key
     * @param lockOperation 加锁以后的操作
     * @author lcy
     * @date 2021/8/20 15:12
     **/
    public static void lockByRedis(String lockKey,LockOperation lockOperation){
        RedissonClient redissonClient = SpringApplicationContext.getBean(RedissonClient.class);
        //获取锁
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock();
            //加锁以后的操作
            lockOperation.lockOperation();
        } finally {
            //释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("解锁成功");
            }
        }
    }

    /**
     * 通过redis加锁操作,并且设置超时时间
     * @param lockKey       锁的key
     * @param timeout       超时时间
     * @param timeUnit      超时时间单位
     * @param lockOperation 加锁以后的操作
     * @author lcy
     * @date 2021/8/20 15:12
     **/
    public static void lockByRedis(String lockKey,long timeout,TimeUnit timeUnit,LockOperation lockOperation){
        RedissonClient redissonClient = SpringApplicationContext.getBean(RedissonClient.class);
        //获取锁
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock(timeout,timeUnit);
            //加锁以后的操作
            lockOperation.lockOperation();
        } finally {
            //释放锁
            if (lock.isLocked()) {
                lock.unlock();
                log.info("解锁成功");
            }
        }
    }

    /**
     * 通过redis加锁操作,并且设置超时时间,单位为秒
     * @param lockKey       锁的key
     * @param timeout       超时时间
     * @param lockOperation 加锁以后的操作
     * @author lcy
     * @date 2021/8/20 15:12
     **/
    public static void lockByRedis(String lockKey,long timeout,LockOperation lockOperation){
        lockByRedis(lockKey,timeout,TimeUnit.SECONDS,lockOperation);
    }
}