java 实现redission分布式锁 笔记

1、pom依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--redisson,redis客户端,封装了分布式锁实现,也可以使用springboot的方式,不需要自己配置-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.12.1</version>
        </dependency>

2、redis yml文件

spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password: 

3、初始化

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

/**
 * 初始化Redission Client
 */
@Configuration
@Order(value = 3)
@Slf4j
public class RedissionConfig {

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.database}")
    private int database;
    @Value("${spring.redis.password}")
    private String password;


    @Bean
    public RedissonClient initRedisson() {

        Config config = new Config();
        //单机模式自动装配
        config.useSingleServer().setAddress("redis://" + host + ":" + port)
                .setDatabase(database);
        if (StringUtils.isNotEmpty(password)) {
            config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(database)
                    .setPassword(password);
        } else {
            config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(database);
        }

//         设置全局默认看门狗机续期时间,如果在使用时不设置,则使用全局的,如果全局不设置,则使用默认的30000,单位毫秒
//         为啥要看门狗:
//            如果业务超长,运行期间自动给锁续上新的有效时间,不用担心业务时间长,锁自动过期被删掉,其实就是可重入锁

        config.setLockWatchdogTimeout(2000);
        log.debug("--------------Redission Client Created------------");
        return Redisson.create(config);
    }
}

4、lock 注解 哪里用放哪里

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁注解
 *
 */

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Dislock {

    /**
     * 分布式锁的key,一般可以用用户id,用户token这种作为唯一的key,达到自己的锁只能被自己解的效果,如#userId
     */
    String localKey() default "";

    /**
     * 业务分类 默认为All不分类,建议分类
     *
     * @return
     */
    String biz() default "ALL";

    /**
     * 锁等待时间 默认2秒
     *
     * @return
     */
    long waitTime() default 2 * 1000;

    /**
     * 锁释放时间 默认2秒
     *
     * @return
     */
    long leaseTime() default 2 * 1000;

    /**
     * 时间格式 默认:毫秒
     *
     * @return
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;

}

 5、解析器

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * lock key 解析器
 */
public class LockKeyParser {

    /**
     * 解析缓存的key
     *
     * @param proceedingJoinPoint 切面
     * @param localKey            lock key
     * @param biz                 业务分类
     * @return String
     * @throws IllegalAccessException 异常
     */
    public static String parse(ProceedingJoinPoint proceedingJoinPoint, String localKey,
                               String biz) throws IllegalAccessException {
        //解析实参
        String key = localKey;
        Object[] parameterValues = proceedingJoinPoint.getArgs();
        MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
        String[] parameterNames = nameDiscoverer.getParameterNames(method);
        String methodName = method.getName();

        if (StringUtils.isEmpty(key)) {
            key = methodName + ":";
            if (parameterNames != null && parameterNames.length > 0) {
                StringBuffer sb = new StringBuffer();
                int i = 0;

                for(int len = parameterNames.length; i < len; ++i) {
                    sb.append(parameterNames[i]).append(" = ").append(parameterValues[i]);
                }

                key += sb.toString();
            } else {
                key = "redissionLock";
            }

            return key;
        } else {
            SpelExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(key);
            if (parameterNames != null && parameterNames.length != 0) {
                EvaluationContext evaluationContext = new StandardEvaluationContext();

                for(int i = 0; i < parameterNames.length; ++i) {
                    evaluationContext.setVariable(parameterNames[i], parameterValues[i]);
                }

                try {
                    Object expressionValue = expression.getValue(evaluationContext);
                    return expressionValue != null && !"".equals(expressionValue.toString()) ? expressionValue.toString() : key;
                } catch (Exception var13) {
                    return key;
                }
            } else {
                return key;
            }
        }
    }



    /**
     * 获取参数Map集合
     *
     * @param joinPoint 切面
     *
     * @return
     */
    private static Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
        Map<String, Object> param = new HashMap<>(paramNames.length);

        for (int i = 0; i < paramNames.length; i++) {
            param.put(paramNames[i], paramValues[i]);
        }
        return param;
    }

    /**
     * 获取指定参数名的参数值
     *
     * @param obj
     * @param propName
     * @return
     *
     * @throws IllegalAccessException
     */
    public static Object getPropValue(Object obj, String propName) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field f : fields) {
            if (f.getName().equals(propName)) {
                //在反射时能访问私有变量
                f.setAccessible(true);
                return f.get(obj);
            }
        }
        return null;
    }

}

 6、切面

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 分布式锁AOP切面类
 */
@Aspect
@Component
public class DislockAspect {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 通过环绕通知实现加锁解锁
     * 切入@Dislock注解的point
     * @param proceedingJoinPoint
     * @return
     *
     * @throws Throwable
     */
    @Around("@annotation(com.xxx.xxx.config.redisson.Dislock)")
    public Object arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object object = null;
        RLock lock = null;
        boolean status = false;
        try {
            Dislock dislock = getDislockInfo(proceedingJoinPoint);
            //生成lockKey,保证锁定资源的唯一性,并且只能解锁自己加的锁
            String lockKey = LockKeyParser.parse(proceedingJoinPoint, dislock.localKey(), dislock.biz());
            lock = redissonClient.getLock(lockKey);
            if (lock != null) {
                //试图加锁
                status = lock.tryLock(dislock.waitTime(), dislock.leaseTime(), dislock.timeUnit());
                if (status) {
//                    System.out.println("lockKey = " + lockKey);
                    //如果加锁成功,执行切点业务
                    object = proceedingJoinPoint.proceed();
                }
            }
        } finally {
            //判断是否需要解锁
            if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return object;
    }

    public Dislock getDislockInfo(ProceedingJoinPoint proceedingJoinPoint) {
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        return methodSignature.getMethod().getAnnotation(Dislock.class);
    }

}

原文地址:基于Redission实现分布式锁(注解版)_redission分布式锁实现-CSDN博客

Redisson 是一个基于 RedisJava 驻内存数据网格(In-Memory Data Grid)。它提供了一些分布式锁实现,包括可重入锁、公平锁、联锁等。下面是使用 Redisson 实现分布式锁的示例代码: 1. 引入 Redisson 依赖 ```xml <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.12.5</version> </dependency> ``` 2. 创建 Redisson 客户端 ```java Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); ``` 3. 获取锁 ```java RLock lock = redisson.getLock("mylock"); lock.lock(); try { // 执行业务逻辑 } finally { lock.unlock(); } ``` 在获取锁时,如果锁已经被其他线程占用,则当前线程会阻塞等待锁的释放。可以通过 `lock.tryLock()` 方法尝试获取锁而不阻塞等待。 ```java RLock lock = redisson.getLock("mylock"); if (lock.tryLock()) { try { // 执行业务逻辑 } finally { lock.unlock(); } } else { // 获取锁失败 } ``` 4. 关闭 Redisson 客户端 ```java redisson.shutdown(); ``` 封装后的分布式锁示例: ```java import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class DistributedLock { private static RedissonClient redisson; static { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); redisson = Redisson.create(config); } public static RLock getLock(String lockKey) { return redisson.getLock(lockKey); } public static void shutdown() { redisson.shutdown(); } } ``` 使用示例: ```java RLock lock = DistributedLock.getLock("mylock"); lock.lock(); try { // 执行业务逻辑 } finally { lock.unlock(); } DistributedLock.shutdown(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值