当前位置:   article > 正文

Spring AOP +redisson的redis分布式锁实现_如何使用aop实现分布式锁

如何使用aop实现分布式锁

      先上效果,rediskey 为第一个从参数的id  最大等待时间为5000毫秒,占用锁之后的自动释放时间为30秒,如果30秒内方法体执行完成,AOP代码会手动释放锁,但是对于写业务的人来说是透明的。

一丶先定义一个注解

  1. package com.util.lock;
  2. import java.lang.annotation.*;
  3. import java.util.concurrent.TimeUnit;
  4. /**
  5. * @description: redis分布式锁
  6. * @createTime: 2022-06-08 09:43
  7. **/
  8. @Target({ElementType.METHOD})
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @Documented
  11. public @interface DistributedLock {
  12. /**
  13. * 锁的名称: 支持spel表达式 eg:#tenantDo.id
  14. * 默认为:类全限定名+'.'+方法名+':' + lockKey eg: com.lzkj.up.service.impl.UserService.getUser:10
  15. */
  16. String lockKey();
  17. /**
  18. * lockKeyPrefix为空时,lockKey使用默认前缀:类全限定名+'.'+方法名+':'
  19. * lockKeyPrefix不为空时,使用lockKeyPrefix作为前缀
  20. * @return
  21. */
  22. String lockKeyPrefix() default "";
  23. /**
  24. * 最长等待时间。默认3秒
  25. * 该字段只有当tryLock()返回true才有效。
  26. */
  27. long waitTime() default 3L;
  28. /**
  29. * 锁超时时间。默认5秒
  30. * 如果tryLock为false,且leaseTime设置为0及以下,会变成lock()
  31. */
  32. long leaseTime() default 30L;
  33. /**
  34. * 时间单位。默认为秒。
  35. */
  36. TimeUnit timeUnit() default TimeUnit.SECONDS;
  37. }

二丶实现aop切面逻辑,使用redission框架 

  1. package com.lock;
  2. import com.alibaba.fastjson.JSONObject;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.aspectj.lang.ProceedingJoinPoint;
  5. import org.aspectj.lang.Signature;
  6. import org.aspectj.lang.annotation.Around;
  7. import org.aspectj.lang.annotation.Aspect;
  8. import org.aspectj.lang.reflect.MethodSignature;
  9. import org.redisson.Redisson;
  10. import org.redisson.api.RLock;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
  13. import org.springframework.expression.EvaluationContext;
  14. import org.springframework.expression.Expression;
  15. import org.springframework.expression.ExpressionParser;
  16. import org.springframework.expression.spel.standard.SpelExpressionParser;
  17. import org.springframework.expression.spel.support.StandardEvaluationContext;
  18. import org.springframework.stereotype.Component;
  19. import java.lang.reflect.Method;
  20. import java.util.HashMap;
  21. import java.util.Map;
  22. /**
  23. * @description: redis分布式锁 aop实现
  24. * @createTime: 2022-06-08 09:54
  25. **/
  26. @Aspect
  27. @Component
  28. @Slf4j
  29. public class DistributedLockAspect {
  30. @Autowired
  31. private Redisson redissonClient;
  32. @Around("@annotation(com.lzkj.up.util.lock.DistributedLock)")
  33. public Object doLock(ProceedingJoinPoint joinPoint) throws Throwable {
  34. Signature signature = joinPoint.getSignature();
  35. MethodSignature methodSignature = (MethodSignature) signature;
  36. Method method = methodSignature.getMethod();
  37. DistributedLock distributedLock = method.getAnnotation(DistributedLock.class);
  38. String lockKey = distributedLock.lockKey();
  39. //获取方法的形参名数组,spring常用,rpc时不需要,反射也不需要。表达式中写形参名
  40. LocalVariableTableParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
  41. String[] parameterNames = nameDiscoverer.getParameterNames(method);
  42. String finalKey = "";
  43. String className = joinPoint.getSignature().getDeclaringTypeName();
  44. Map<String, Object> hashMap = new HashMap<>();
  45. if (parameterNames != null && parameterNames.length > 0) {
  46. //spel表达式解析
  47. ExpressionParser parser = new SpelExpressionParser();
  48. EvaluationContext context = new StandardEvaluationContext();
  49. Expression expression = parser.parseExpression(lockKey);
  50. //存储形参和传值的映射
  51. //获取方法传入的参数值
  52. Object[] args = joinPoint.getArgs();
  53. for (int i = 0; i < parameterNames.length; i++) {
  54. //建立形参名和值的映射关系,存入上下文当中,后面取出表达式带有的形参
  55. context.setVariable(parameterNames[i], args[i]);
  56. hashMap.put(parameterNames[i], args[i]);
  57. }
  58. //这里取字符串类型作为key
  59. String newKey = expression.getValue(context, String.class);
  60. finalKey = className + "." + method.getName() + ":" + newKey;
  61. } else {
  62. finalKey = className + "." + method.getName() + ":" + lockKey;
  63. }
  64. log.info("DistributedLock finalKey=[{}]开始上锁,参数为:{}", finalKey, JSONObject.toJSONString(hashMap));
  65. RLock lock = redissonClient.getLock(finalKey);
  66. boolean res = lock(lock, distributedLock);
  67. long currentThreadId = Thread.currentThread().getId();
  68. if (res) {
  69. log.info("获取锁成功:{}",currentThreadId);
  70. try {
  71. log.info("DistributedLock finalKey=[{}],方法运行结束", finalKey);
  72. return joinPoint.proceed();
  73. } catch (Throwable e) {
  74. log.error("DistributedLock: finalKey: {} 业务异常", finalKey);
  75. throw new BusinessException("500",e.getMessage());
  76. } finally {
  77. if (lock.isLocked() && lock.isHeldByCurrentThread()) {
  78. lock.unlock();
  79. }
  80. }
  81. } else {
  82. log.warn("DistributedLock: finalKey: {} 获取锁失败:{}",finalKey,currentThreadId);
  83. throw new BusinessException("400","获取锁失败,请稍后重试");
  84. }
  85. }
  86. private boolean lock(RLock lock, DistributedLock distributedLock) {
  87. boolean result;
  88. // 上锁
  89. try {
  90. result = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), distributedLock.timeUnit());
  91. } catch (InterruptedException e) {
  92. log.error("DistributedLock InterruptedException",e);
  93. result = false;
  94. }
  95. return result;
  96. }
  97. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/397819
推荐阅读
相关标签
  

闽ICP备14008679号