content: package org.jeecg.boot.starter.lock.aspect;
  
  import lombok.SneakyThrows;
  import lombok.extern.slf4j.Slf4j;
  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.jeecg.boot.starter.lock.annotation.JLock;
  import org.jeecg.boot.starter.lock.enums.LockModel;
  import org.redisson.RedissonMultiLock;
  import org.redisson.RedissonRedLock;
  import org.redisson.api.RLock;
  import org.redisson.api.RedissonClient;
  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.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.TimeUnit;
  
  
  /**
   * 分布式锁解析器
   *
   * @author zyf
   * @date 2020-11-11
   */
  @Slf4j
  @Aspect
  @Component
  public class DistributedLockHandler extends BaseAspect{
  
  
      @Autowired(required = false)
      private RedissonClient redissonClient;
  
      /**
       * 切面环绕通知
       *
       * @param joinPoint
       * @param jLock
       * @return Object
       */
      @SneakyThrows
      @Around("@annotation(jLock)")
      public Object around(ProceedingJoinPoint joinPoint, JLock jLock) {
          Object obj = null;
          log.info("进入RedisLock环绕通知...");
          RLock rLock = getLock(joinPoint, jLock);
          boolean res = false;
          //获取超时时间
          long expireSeconds = jLock.expireSeconds();
          //等待多久,n秒内获取不到锁，则直接返回
          long waitTime = jLock.waitTime();
          //执行aop
          if (rLock != null) {
              try {
                  if (waitTime == -1) {
                      res = true;
                      //一直等待加锁
                      rLock.lock(expireSeconds, TimeUnit.MILLISECONDS);
                  } else {
                      res = rLock.tryLock(waitTime, expireSeconds, TimeUnit.MILLISECONDS);
                  }
                  if (res) {
                      obj = joinPoint.proceed();
                  } else {
                      log.error("获取锁异常");
                  }
              } finally {
                  if (res) {
                      rLock.unlock();
                  }
              }
          }
          log.info("结束RedisLock环绕通知...");
          return obj;
      }
  
      @SneakyThrows
      private RLock getLock(ProceedingJoinPoint joinPoint, JLock jLock) {
          String[] keys = jLock.lockKey();
          if (keys.length == 0) {
              throw new RuntimeException("keys不能为空");
          }
          String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());
          Object[] args = joinPoint.getArgs();
  
          LockModel lockModel = jLock.lockModel();
          if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) {
              throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定");
          }
          RLock rLock = null;
          String keyConstant = jLock.keyConstant();
          if (lockModel.equals(LockModel.AUTO)) {
              if (keys.length > 1) {
                  lockModel = LockModel.REDLOCK;
              } else {
                  lockModel = LockModel.REENTRANT;
              }
          }
          switch (lockModel) {
              case FAIR:
                  rLock = redissonClient.getFairLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0));
                  break;
              case REDLOCK:
                  List<RLock> rLocks = new ArrayList<>();
                  for (String key : keys) {
                      List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
                      for (String s : valueBySpEL) {
                          rLocks.add(redissonClient.getLock(s));
                      }
                  }
                  RLock[] locks = new RLock[rLocks.size()];
                  int index = 0;
                  for (RLock r : rLocks) {
                      locks[index++] = r;
                  }
                  rLock = new RedissonRedLock(locks);
                  break;
              case MULTIPLE:
                  rLocks = new ArrayList<>();
  
                  for (String key : keys) {
                      List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
                      for (String s : valueBySpEL) {
                          rLocks.add(redissonClient.getLock(s));
                      }
                  }
                  locks = new RLock[rLocks.size()];
                  index = 0;
                  for (RLock r : rLocks) {
                      locks[index++] = r;
                  }
                  rLock = new RedissonMultiLock(locks);
                  break;
              case REENTRANT:
                  List<String> valueBySpEL = getValueBySpEL(keys[0], parameterNames, args, keyConstant);
                  //如果spel表达式是数组或者LIST 则使用红锁
                  if (valueBySpEL.size() == 1) {
                      rLock = redissonClient.getLock(valueBySpEL.get(0));
                  } else {
                      locks = new RLock[valueBySpEL.size()];
                      index = 0;
                      for (String s : valueBySpEL) {
                          locks[index++] = redissonClient.getLock(s);
                      }
                      rLock = new RedissonRedLock(locks);
                  }
                  break;
              case READ:
                  rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).readLock();
                  break;
              case WRITE:
                  rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).writeLock();
                  break;
          }
          return rLock;
      }
  }
  