前言
有个需求要求做幂等,按之前的做法,在业务代码中使用 redis 根据幂等标识获取值,有则证明该入参短时间内已触发过,滤过。然后再业务结尾,将幂等标识发送个redis
注:以上幂等有个问题,两个相同的入参同时进入,同样再redis上是找不到幂等标识的,此时第一个入参没有将幂等标识发送到redis上 第二个入参同样也能进入业务代码,会有巨大的问题,所以,基于该问题的考虑,我决定使用redis分布式锁,来做幂等
这段代码与业务代码其实毫无关联,趁着开发时间有余,把这一块封装出来使用aop完成。
此时需要一个注解,需要从方法的入参中拿到需要幂等标识,如果写死,这个注解的通用性就此吃了屎,所以想到使用spEl去取,入参中的值,spring的部分注解是自动支持spEl取值的,自定义的注解就别想了,需要自己手动搞。
代码
幂等注解
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Idempotent { String key(); }
aop实现
@Around("idempotentPointCut() && @annotation(idempotent)") public Object around(ProceedingJoinPoint point, Idempotent idempotent) throws Throwable { String key = "Idempotent" + parseSpEl(point, idempotent.key()); RLock lock = redissonClient.getLock(key + "lock"); try { if (lock.tryLock(30, 60,TimeUnit.SECONDS)){ return point.proceed(); } } catch (Throwable e) { log.error("获取分布式锁过程报错!!", e); lock.unlock(); throw e; } finally { lock.unlock(); } } private Object parseSpEl(ProceedingJoinPoint point, String key) { MethodSignature signature = (MethodSignature) point.getSignature(); List<String> paramNameList = Arrays.asList(signature.getParameterNames()); List<Object> paramList = Arrays.asList(point.getArgs()); //将方法的参数名和参数值一一对应的放入上下文中 EvaluationContext ctx = new StandardEvaluationContext(); for (int i = 0; i < paramNameList.size(); i++) { ctx.setVariable(paramNameList.get(i), paramList.get(i)); } // 解析SpEL表达式获取结果 return spelParser.parseExpression(key).getValue(ctx); }
标签:point,lock,redis,spEl,key,注解,解析 From: https://www.cnblogs.com/cgdq/p/17614191.html