0
点赞
收藏
分享

微信扫一扫

使用redisson设计一个分布式的锁

潇湘落木life 2022-04-01 阅读 83
java-ee
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.11.5</version>
</dependency>

这里是在aop的基础上使用自定义注解,对需要进行加锁的业务进行环绕通知。共需要用到一个redisson工具类、自定义注解类、Aop通知逻辑、业务测试类,分别如下。

1、redisson工具类

@Component
public class RedisLockUtils {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 可重入,!线程不主动解锁将会永远存在! 慎用
     */
    public void lock(String lockKey){
        RLock lock = redissonClient.getLock(lockKey);
        redissonClient.getRedLock(lock).lock();
    }

    public void lock(String lockKey, Runnable runnable){
        lock(lockKey);
        try {
            runnable.run();
        } finally {
            this.unLock(lockKey);
        }
    }

    /**
     * 拿到索 并设置一个超时时间
     * @param lockKey
     * @param leaseTime
     */
    public void lock(String lockKey, long leaseTime) {
        RLock lock1 = redissonClient.getLock(lockKey);
        redissonClient.getRedLock(lock1).lock(leaseTime, TimeUnit.MILLISECONDS);
    }

    public void lock(String lockKey, long leaseTime, Runnable runnable) {
        lock(lockKey, leaseTime);
        try {
            runnable.run();
        } finally {
            this.unLock(lockKey);
        }
    }

    /**
     * 在一定时间内获取某个锁 并且设置锁的超时时间
     * @param lockKey 锁
     * @param waitTime 争夺所的时间段
     * @param leaseTime 锁的超时时间
     * @return
     * @throws InterruptedException
     */
    public boolean tryLockTimeout(String lockKey,long waitTime, long leaseTime) throws InterruptedException {
        RLock lock1 = redissonClient.getLock(lockKey);
        return redissonClient.getRedLock(lock1).tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
    }


    public boolean tryLockTimeout(String lockKey, long waitTime, long leaseTime, Runnable runnable) throws InterruptedException {
        if (tryLockTimeout(lockKey, waitTime, leaseTime)) {
            try {
                runnable.run();
            } finally {
                this.unLock(lockKey);
            }
            return true;
        }
        return false;
    }


    public void unLock(String lockKey) {
        RLock lock1 = redissonClient.getLock(lockKey);
        redissonClient.getRedLock(lock1).unlock();
    }

}

其中redisssonClient注入方式如下

@Value("${spring.redis.host}")
private String host;

@Value("${spring.redis.port}")
private String port;

@Value("${spring.redis.password}")
private String password;


@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(){
    Config config = new Config();
    SingleServerConfig singleServerConfig = config.useSingleServer().setAddress("redis://" + host + ":" + port);
    if(StringUtils.isNotBlank(password)){
        singleServerConfig.setPassword(password);
    }
    return Redisson.create(config);
}

2、自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLock {

    String lockValue() default  "zyht";

}

3、Aop通知逻辑

import com.emergency.common.entity.AjaxResult;
import com.emergency.config.custom_annotation.RedisLock;
import com.emergency.config.util.RedisLockUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class RedisLocAop {

    static Logger logger = LoggerFactory.getLogger(RedisLocAop.class);

    @Pointcut("@annotation(com.emergency.config.custom_annotation.RedisLock)" )
    public void redisLockAdvice(){}

    @Autowired
    private RedisLockUtils redisLockUtils;

    @Around("redisLockAdvice()")
    public Object Interceptor(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature msg=(MethodSignature) joinPoint.getSignature();
        //拿到注解标注的方法
        Method method = joinPoint.getTarget().getClass().getMethod(msg.getName(), msg.getParameterTypes());
        //拿到注解
        RedisLock annotation = method.getAnnotation(RedisLock.class);
        String lockKey = annotation.lockValue();
        boolean isLock = false;
        try {
            //1.拿到锁
            //(5000毫秒尝试获取锁, 锁定后10000毫秒锁过期自动释放,最大容差为5000毫秒,注意方法执行时间).
            //2.注力度,满足最大容差即可
            isLock = redisLockUtils.tryLockTimeout(lockKey, 5000, 10000);
            //5000毫秒超时未获得锁
            if(!isLock ){
                return AjaxResult.error("业务繁忙,请重试。");
            }
            //锁获得后,执行业务
            logger.info("执行方法:{},并拿到锁。",joinPoint.getSignature().getName());
            Object result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            logger.error("run error:", e);
            return AjaxResult.error("执行方法:{},出现异常。",joinPoint.getSignature().getName());
        }finally {
            //解锁
            if(isLock) {
                redisLockUtils.unLock(lockKey);
            }
        }

    }

}

4、用于测试

@Override
@RedisLock(lockValue = "00000001")
public AjaxResult method1() throws InterruptedException {
    Thread.sleep(3000);
    return AjaxResult.success();

}

@Override
@RedisLock(lockValue = "00000001")
public AjaxResult method2() throws InterruptedException {
    Thread.sleep(3000);
    return AjaxResult.success();

}
举报

相关推荐

0 条评论