Springboot+Aop注解的方式实现分布式锁

公司做分布式的订单业务,需要增加分布式锁进行竞争资源,需要增加锁降级功能

简单实现了一下,支持 SPEL ,有更好的建议尽情提出

注解代码:

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface CacheLock {

     /**

      * 支持 SPEL 表达式

      */

     String key();

 

     long expTime() default 10;

 

     TimeUnit timeUnit() default TimeUnit.SECONDS;

}

AOP 切面:

@Slf4j

@Aspect

@Component

public class CacheLockAop {

     /**

      * 最大等待时间 ms

      */

     private static final long MAX_WAIT_TIME = 30000;

     @Resource

     private Redisson orderRedisson;

     @Around("@within(cacheLock) || @annotation(cacheLock)")

     public Object cacheLock(ProceedingJoinPoint jp, CacheLock cacheLock) throws Throwable {

         Object result = Response.fail(CodeEnum.ERROR.getCode(), CodeEnum.ERROR.getMsg());

         boolean locked = false;

         try {

             String lockKey = CacheKeyConstant.ORDER_LOCK_KEY + this.getLockKey(jp, cacheLock.key());

             log.info("CacheLockAop#cacheLock 获取 key {}", lockKey);

             RLock rLock = orderRedissonExt.getLock(lockKey);

             locked = rLock.tryLock(cacheLock.timeUnit().convert(MAX_WAIT_TIME, TimeUnit.MILLISECONDS), cacheLock.expTime(), cacheLock.timeUnit());

             if (locked) {

                 try {

                     result = jp.proceed();

                 } finally {

                     rLock.unlock();

                 }

             } else {

                 log.error("CacheLockAop#cacheLock 外汇跟单gendan5.com 缓存锁获取失败, key {}", lockKey);

                 result = Response.fail(CodeEnum.ERROR.getCode(), " 缓存锁获取失败,请稍后重试 ");

             }

         } catch (Throwable e) {

             log.error("CacheLockAop#cacheLock ERROR", e);

             // 异常后没有获取锁执行业务代码

             if (!locked) {

                 log.warn(" 缓存锁添加失败,降级执行 ...");

                 result = jp.proceed();

             }

         }

         return result;

     }

     private String getLockKey(ProceedingJoinPoint jp, String elStr) throws NoSuchMethodException {

         LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

         EvaluationContext context = new StandardEvaluationContext();

         String[] paraNameArr = discoverer.getParameterNames(this.getTargetMethod(jp));

         Object[] args = jp.getArgs();

         for (int i = 0; i < paraNameArr.length; i++) {

             context.setVariable(paraNameArr[i], args[i]);

         }

         ExpressionParser expressionParser = new SpelExpressionParser();

         Expression expression = expressionParser.parseExpression(elStr);

         String lockKey = expression.getValue(context, String.class);

         if (StringUtils.isBlank(lockKey)) {

             throw new RuntimeException("CacheLockAop#getLockKey 获取 lockKey 为空! ");

         }

         return lockKey;

     }

     private Method getTargetMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {

         Signature signature = pjp.getSignature();

         MethodSignature methodSignature = (MethodSignature) signature;

         Method agentMethod = methodSignature.getMethod();

         return pjp.getTarget().getClass().getMethod(agentMethod.getName(), agentMethod.getParameterTypes());

     }

}

使用方法:

     @Override

     @CacheLock(key = "#orderReq.srcSystem + '_' + #orderReq.orderId")

     public Response submitOrder(OrderReq orderReq) {

         // 你的业务代码

     }


请使用浏览器的分享功能分享到微信等