小工具知识网

当前位置: 首页 > 行业知识 > Spring Boot 集成 Redisson分布式锁(注解版)

行业知识

Spring Boot 集成 Redisson分布式锁(注解版)

2026-11-04 17:22:26 来源:互联网转载

        Redisson 是一种基于 Redis 的 Java 驻留集群的分布式对象和服务库,可以为我们提供丰富的分布式锁和线程安全集合的实现。在 Spring Boot 应用程序中使用 Redisson 可以方便地实现分布式应用程序的某些方面,例如分布式锁、分布式集合、分布式事件发布和订阅等。本篇是一个使用 Redisson 实现分布式锁的详细示例,在这个示例中,我们定义了DistributedLock注解,它可以标注在方法上,配合DistributedLockAspect切面以及IDistributedLock分布式锁封装的接口,来实现redisson 分布式锁的 API 调用。

Spring Boot 集成 Redisson

 1、在 pom.xml 文件中添加 Redisson 的相关依赖

    org.redisson    redisson-spring-boot-starter    3.16.1

2、在 application.yml 中配置 Redisson单机模式 的连接信息和相关参数

spring:  redis:    host: localhost    port: 6379    password: nullredisson:  codec: org.redisson.codec.JsonJacksonCodec  threads: 4  netty:    threads: 4  single-server-config:    address: "redis://localhost:6379"    password: null    database: 0

3、Redission还支持主从、集群、哨兵配置

//主从模式spring:  redis:    sentinel:      master: my-master      nodes: localhost:26379,localhost:26389    password: your_passwordredisson:  master-slave-config:    master-address: "redis://localhost:6379"    slave-addresses: "redis://localhost:6380,redis://localhost:6381"    password: ${spring.redis.password}// 集群模式spring:  redis:    cluster:      nodes: localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384    password: your_passwordredisson:  cluster-config:    node-addresses: "redis://localhost:6379,redis://localhost:6380,redis://localhost:6381,redis://localhost:6382,redis://localhost:6383,redis://localhost:6384"    password: ${spring.redis.password}// 哨兵模式spring:  redis:    sentinel:      master: my-master      nodes: localhost:26379,localhost:26389    password: your_passwordredisson:  sentinel-config:    master-name: my-master    sentinel-addresses: "redis://localhost:26379,redis://localhost:26380,redis://localhost:26381"    password: ${spring.redis.password}

 本地封装Redisson 分布式锁

1、定义IDistributedLock分布式锁接口

public interface IDistributedLock {    /**     * 获取锁,默认30秒失效,失败一直等待直到获取锁     *     * @param key 锁的key     * @return 锁对象     */    ILock lock(String key);    /**     * 获取锁,失败一直等待直到获取锁     *     * @param key      锁的key     * @param lockTime 加锁的时间,超过这个时间后锁便自动解锁; 如果lockTime为-1,则保持锁定直到显式解锁     * @param unit     {@code lockTime} 参数的时间单位     * @param fair     是否公平锁     * @return 锁对象     */    ILock lock(String key, long lockTime, TimeUnit unit, boolean fair);    /**     * 尝试获取锁,30秒获取不到超时异常,锁默认30秒失效     *     * @param key     锁的key     * @param tryTime 获取锁的最大尝试时间     * @return     * @throws Exception     */    ILock tryLock(String key, long tryTime) throws Exception;    /**     * 尝试获取锁,获取不到超时异常     *     * @param key      锁的key     * @param tryTime  获取锁的最大尝试时间     * @param lockTime 加锁的时间     * @param unit     {@code tryTime @code lockTime} 参数的时间单位     * @param fair     是否公平锁     * @return     * @throws Exception     */    ILock tryLock(String key, long tryTime, long lockTime, TimeUnit unit, boolean fair) throws Exception;    /**     * 解锁     *     * @param lock     * @throws Exception     */    void unLock(Object lock);    /**     * 释放锁     *     * @param lock     * @throws Exception     */    default void unLock(ILock lock) {        if (lock != null) {            unLock(lock.getLock());        }    }}

2、IDistributedLock实现类

@Slf4j@Componentpublic class RedissonDistributedLock implements IDistributedLock {    @Resource    private RedissonClient redissonClient;    /**     * 统一前缀     */    @Value("${redisson.lock.prefix:bi:distributed:lock}")    private String prefix;    @Override    public ILock lock(String key) {        return this.lock(key, 0L, TimeUnit.SECONDS, false);    }    @Override    public ILock lock(String key, long lockTime, TimeUnit unit, boolean fair) {        RLock lock = getLock(key, fair);        // 获取锁,失败一直等待,直到获取锁,不支持自动续期        if (lockTime > 0L) {            lock.lock(lockTime, unit);        } else {            // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s            lock.lock();        }        return new ILock(lock, this);    }    @Override    public ILock tryLock(String key, long tryTime) throws Exception {        return this.tryLock(key, tryTime, 0L, TimeUnit.SECONDS, false);    }    @Override    public ILock tryLock(String key, long tryTime, long lockTime, TimeUnit unit, boolean fair)            throws Exception {        RLock lock = getLock(key, fair);        boolean lockAcquired;        // 尝试获取锁,获取不到超时异常,不支持自动续期        if (lockTime > 0L) {            lockAcquired = lock.tryLock(tryTime, lockTime, unit);        } else {            // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s            lockAcquired = lock.tryLock(tryTime, unit);        }        if (lockAcquired) {            return new ILock(lock, this);        }        return null;    }    /**     * 获取锁     *     * @param key     * @param fair     * @return     */    private RLock getLock(String key, boolean fair) {        RLock lock;        String lockKey = prefix + ":" + key;        if (fair) {            // 获取公平锁            lock = redissonClient.getFairLock(lockKey);        } else {            // 获取普通锁            lock = redissonClient.getLock(lockKey);        }        return lock;    }    @Override    public void unLock(Object lock) {        if (!(lock instanceof RLock)) {            throw new IllegalArgumentException("Invalid lock object");        }        RLock rLock = (RLock) lock;        if (rLock.isLocked()) {            try {                rLock.unlock();            } catch (IllegalMonitorStateException e) {                log.error("释放分布式锁异常", e);            }        }    }}

 3、定义ILock锁对象

import lombok.AllArgsConstructor;import lombok.Getter;import java.util.Objects;/** * 

* RedissonLock 包装的锁对象 实现AutoCloseable接口,在java7的try(with resource)语法,不用显示调用close方法 *

* @since 2023-06-08 16:57 */@AllArgsConstructorpublic class ILock implements AutoCloseable { /** * 持有的锁对象 */ @Getter private Object lock; /** * 分布式锁接口 */ @Getter private IDistributedLock distributedLock; @Override public void close() throws Exception { if(Objects.nonNull(lock)){ distributedLock.unLock(lock); } }}

4、注入IDistributedLock接口使用示例

// 定义接口public interface IProductSkuSupplierMeasureService {    /**     * 保存SKU供应商供货信息     *     * @param dto     * @return     *    Boolean saveSupplierInfo(ProductSkuSupplierInfoDTO dto);    /**     * 编辑SKU供应商供货信息     *     * @param dto     * @return     */    Boolean editSupplierInfo(ProductSkuSupplierInfoDTO dto);}    

手动释放锁示例 

// 实现类@Servicepublic class ProductSkuSupplierMeasureServiceImpl         implements IProductSkuSupplierMeasureService {    @Resource    private IDistributedLock distributedLock;            @Override    @Transactional(rollbackFor = Exception.class)    public Boolean saveSupplierInfo(ProductSkuSupplierInfoDTO dto) {        // 手动释放锁        String sku = dto.getSku();        ILock lock = null;        try {            lock = distributedLock.lock(dto.getSku(),10L, TimeUnit.SECONDS, false);            if (Objects.isNull(lock)) {                throw new BusinessException("Duplicate request for method still in process");            }            // 业务代码        }catch (BusinessException e) {            throw new BusinessException(e.getMessage());        } catch (Exception e) {            log.error("保存异常", e);            throw new BusinessException (e.getMessage());        } finally {            if (Objects.nonNull(lock)) {                distributedLock.unLock(lock);            }        }        return Boolean.TRUE;    }}

 使用try-with-resources 语法糖自动释放锁

// 实现类@Servicepublic class ProductSkuSupplierMeasureServiceImpl         implements IProductSkuSupplierMeasureService {    @Resource    private IDistributedLock distributedLock;           @Override    @Transactional(rollbackFor = Exception.class)    public Boolean editSupplierInfo(ProductSkuSupplierInfoDTO dto) {               String sku = dto.getSku();        // try-with-resources 语法糖自动释放锁        try(ILock lock = distributedLock.lock(dto.getSku(),10L, TimeUnit.SECONDS, false)) {            if(Objects.isNull(lock)){                throw new BusinessException ("Duplicate request for method still in process");            }                        // 业务代码        }catch (BusinessException e) {            throw new BusinessException (e.getMessage());        } catch (Exception e) {            log.error("修改异常", e);            throw new BusinessException ("修改异常");        }        return Boolean.TRUE;   }}

5、使用AOP切面实现分布式锁的绑定

  定义DistributedLock注解

@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface DistributedLock {    /**     * 保证业务接口的key的唯一性,否则失去了分布式锁的意义 锁key     * 支持使用spEl表达式     */    String key();    /**     * 保证业务接口的key的唯一性,否则失去了分布式锁的意义 锁key 前缀     */    String keyPrefix() default "";    /**     * 是否在等待时间内获取锁,如果在等待时间内无法获取到锁,则返回失败     */    boolean tryLok() default false;    /**     * 获取锁的最大尝试时间 ,会尝试tryTime时间获取锁,在该时间内获取成功则返回,否则抛出获取锁超时异常,tryLok=true时,该值必须大于0。     *     */    long tryTime() default 0;    /**     * 加锁的时间,超过这个时间后锁便自动解锁     */    long lockTime() default 30;    /**     * tryTime 和 lockTime的时间单位     */    TimeUnit unit() default TimeUnit.SECONDS;    /**     * 是否公平锁,false:非公平锁,true:公平锁     */    boolean fair() default false;}

 定义DistributedLockAspect Lock切面

@Aspect@Slf4jpublic class DistributedLockAspect {    @Resource    private IDistributedLock distributedLock;    /**     * SpEL表达式解析     */    private SpelExpressionParser spelExpressionParser = new SpelExpressionParser();    /**     * 用于获取方法参数名字     */    private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();    @Pointcut("@annotation(com.yt.bi.common.redis.distributedlok.annotation.DistributedLock)")    public void distributorLock() {    }    @Around("distributorLock()")    public Object around(ProceedingJoinPoint pjp) throws Throwable {        // 获取DistributedLock        DistributedLock distributedLock = this.getDistributedLock(pjp);        // 获取 lockKey        String lockKey = this.getLockKey(pjp, distributedLock);        ILock lockObj = null;        try {            // 加锁,tryLok = true,并且tryTime > 0时,尝试获取锁,获取不到超时异常            if (distributedLock.tryLok()) {                if(distributedLock.tryTime() 

上一篇:双网卡服务器怎么接网络?

下一篇:宝塔面板花屏问题解析与修复指南!