赞
踩
先上效果,rediskey 为第一个从参数的id 最大等待时间为5000毫秒,占用锁之后的自动释放时间为30秒,如果30秒内方法体执行完成,AOP代码会手动释放锁,但是对于写业务的人来说是透明的。
一丶先定义一个注解
- package com.util.lock;
-
- import java.lang.annotation.*;
- import java.util.concurrent.TimeUnit;
-
- /**
- * @description: redis分布式锁
- * @createTime: 2022-06-08 09:43
- **/
- @Target({ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface DistributedLock {
- /**
- * 锁的名称: 支持spel表达式 eg:#tenantDo.id
- * 默认为:类全限定名+'.'+方法名+':' + lockKey eg: com.lzkj.up.service.impl.UserService.getUser:10
- */
- String lockKey();
-
- /**
- * lockKeyPrefix为空时,lockKey使用默认前缀:类全限定名+'.'+方法名+':'
- * lockKeyPrefix不为空时,使用lockKeyPrefix作为前缀
- * @return
- */
- String lockKeyPrefix() default "";
-
- /**
- * 最长等待时间。默认3秒
- * 该字段只有当tryLock()返回true才有效。
- */
- long waitTime() default 3L;
-
- /**
- * 锁超时时间。默认5秒
- * 如果tryLock为false,且leaseTime设置为0及以下,会变成lock()
- */
- long leaseTime() default 30L;
-
- /**
- * 时间单位。默认为秒。
- */
- TimeUnit timeUnit() default TimeUnit.SECONDS;
-
- }
二丶实现aop切面逻辑,使用redission框架
- package com.lock;
-
- import com.alibaba.fastjson.JSONObject;
- import lombok.extern.slf4j.Slf4j;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.Signature;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.reflect.MethodSignature;
- import org.redisson.Redisson;
- import org.redisson.api.RLock;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
- import org.springframework.expression.EvaluationContext;
- import org.springframework.expression.Expression;
- import org.springframework.expression.ExpressionParser;
- import org.springframework.expression.spel.standard.SpelExpressionParser;
- import org.springframework.expression.spel.support.StandardEvaluationContext;
- import org.springframework.stereotype.Component;
-
- import java.lang.reflect.Method;
- import java.util.HashMap;
- import java.util.Map;
-
- /**
- * @description: redis分布式锁 aop实现
- * @createTime: 2022-06-08 09:54
- **/
- @Aspect
- @Component
- @Slf4j
- public class DistributedLockAspect {
-
- @Autowired
- private Redisson redissonClient;
-
- @Around("@annotation(com.lzkj.up.util.lock.DistributedLock)")
- public Object doLock(ProceedingJoinPoint joinPoint) throws Throwable {
- Signature signature = joinPoint.getSignature();
- MethodSignature methodSignature = (MethodSignature) signature;
- Method method = methodSignature.getMethod();
- DistributedLock distributedLock = method.getAnnotation(DistributedLock.class);
- String lockKey = distributedLock.lockKey();
- //获取方法的形参名数组,spring常用,rpc时不需要,反射也不需要。表达式中写形参名
- LocalVariableTableParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
- String[] parameterNames = nameDiscoverer.getParameterNames(method);
- String finalKey = "";
- String className = joinPoint.getSignature().getDeclaringTypeName();
- Map<String, Object> hashMap = new HashMap<>();
- if (parameterNames != null && parameterNames.length > 0) {
- //spel表达式解析
- ExpressionParser parser = new SpelExpressionParser();
- EvaluationContext context = new StandardEvaluationContext();
- Expression expression = parser.parseExpression(lockKey);
- //存储形参和传值的映射
- //获取方法传入的参数值
- Object[] args = joinPoint.getArgs();
- for (int i = 0; i < parameterNames.length; i++) {
- //建立形参名和值的映射关系,存入上下文当中,后面取出表达式带有的形参
- context.setVariable(parameterNames[i], args[i]);
- hashMap.put(parameterNames[i], args[i]);
- }
- //这里取字符串类型作为key
- String newKey = expression.getValue(context, String.class);
- finalKey = className + "." + method.getName() + ":" + newKey;
- } else {
- finalKey = className + "." + method.getName() + ":" + lockKey;
- }
- log.info("DistributedLock finalKey=[{}]开始上锁,参数为:{}", finalKey, JSONObject.toJSONString(hashMap));
- RLock lock = redissonClient.getLock(finalKey);
- boolean res = lock(lock, distributedLock);
- long currentThreadId = Thread.currentThread().getId();
- if (res) {
- log.info("获取锁成功:{}",currentThreadId);
- try {
- log.info("DistributedLock finalKey=[{}],方法运行结束", finalKey);
- return joinPoint.proceed();
- } catch (Throwable e) {
- log.error("DistributedLock: finalKey: {} 业务异常", finalKey);
- throw new BusinessException("500",e.getMessage());
- } finally {
- if (lock.isLocked() && lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- } else {
- log.warn("DistributedLock: finalKey: {} 获取锁失败:{}",finalKey,currentThreadId);
- throw new BusinessException("400","获取锁失败,请稍后重试");
- }
- }
-
-
- private boolean lock(RLock lock, DistributedLock distributedLock) {
- boolean result;
- // 上锁
- try {
- result = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), distributedLock.timeUnit());
- } catch (InterruptedException e) {
- log.error("DistributedLock InterruptedException",e);
- result = false;
- }
- return result;
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。