SpringBoot 自定义注解,轻松实现 Redis 分布式锁

1.自定义注解类

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ReqFastLimit {
    //redis key
    String key() default "";
    //过期时间 单位秒
    long expire() default 60L;
  // 前缀
    String prefix() default "";
}

2.定义切面

@Aspect
@Component
@Slf4j
@SuppressWarnings("ALL")
public class ReqFastHandler {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private HttpServletRequest request;

    @Around(("@annotation(reqFastLimit)"))
    public Object around(ProceedingJoinPoint joinPoint, ReqFastLimit reqFastLimit) throws Throwable {
        String requestURI = request.getRequestURI();
        String keySpel = reqFastLimit.key();
        long expire = reqFastLimit.expire();
        String prefix = reqFastLimit.prefix();
        Object[] args = joinPoint.getArgs();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        //获取被拦截方法参数名列表(使用Spring支持类库)
        LocalVariableTableParameterNameDiscoverer localVariableTable = new LocalVariableTableParameterNameDiscoverer();
        String[] paraNameArr = localVariableTable.getParameterNames(method);
        //使用SPEL进行key的解析
        ExpressionParser parser = new SpelExpressionParser();
        //SPEL上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        //把方法参数放入SPEL上下文中
        for (int i = 0; i < paraNameArr.length; i++) {
            context.setVariable(paraNameArr[i], args[i]);
        }
        String key = null;
        // 使用变量方式传入业务动态数据
        if (keySpel.matches("^#.*.$")) {
            String[] split = keySpel.split(",");
            for (String s : split) {
                if (key == null) {
                    key = parser.parseExpression(s).getValue(context, String.class);
                } else {
                    key = key + ":" + parser.parseExpression(s).getValue(context, String.class);
                }
            }
        }
        try {
            Boolean result = redisTemplate.opsForValue().setIfAbsent(prefix + key, key, expire, TimeUnit.SECONDS);
            if (!result) {
                log.info("key={}", prefix + key);
                throw new Exception("您手速真快,慢点吧!");
            }
            return joinPoint.proceed();
        } catch (CustomException e) {
            throw e;
        } finally {
          //代码逻辑执行完释放锁
            redisTemplate.delete(prefix + key);
        }

    }

3.注解使用

    @ReqFastLimit(key = "#test.orderNo,#test.channo", expire = 3, prefix = "test")
    public ResultVo test(@RequestBody @Valid Test test) {
        return testService.test(test);
    }

4.效果

 

posted @ 2022-11-13 17:11  BlackCatFish  阅读(314)  评论(0编辑  收藏  举报