LocalLock 本地锁 实现拒绝重复提交

本地锁的基本使用

LocalLock 本地锁

实现 拒绝一个请求在规定时间多次调用

1实现原理

当一个请求被提交,把请求方法的参数存到redis并设置过期时间(比如5秒),如果5秒内再次请求,redis中就可以查到信息,直接拒绝请求,否则正常通过
使用Spring AOP 对注解方法进行切面:

  1. ​ 从redis中 通过获取注解传入的参数 来查询数据
  2. ​ 如果不存在,就执行方法,并将参数为key放入redis,并设置过期时间为规定不可重复时间
  3. ​ 如果存在,就抛出异常,停止执行方法

2实现代码

注解类:

/**
 * @author : lzcer
 * @date : 2020/11/9 8:45
 * @description : 本地锁
 * Target     注解目标 方法
 * Retention  保留注解的策略
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LocalLock {
    /*
    定义属性key
     */
    String key() default "";
}

切面类:

/**
 * @author lzcer
 */
@Aspect
@Configuration
public class LocalMethodInterceptor {
    private static final Cache<String, Object> CACHE = CacheBuilder.newBuilder()
            //最大缓存个数
            .maximumSize(100)
            //缓存5秒过期
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .build();

    @Around("execution(public  * *(..))&& @annotation(com.lzcer.care_free_final.framework.annotation.LocalLock)")
    public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        LocalLock localLock = method.getAnnotation(LocalLock.class);
        String key = getKey(localLock.key(), pjp.getArgs());
        if (!StringUtils.isEmpty(key)) {
            String cache = redisCache.getCacheObject(key);
            if (cache != null && !"".equals(cache)) {
                //有这个key 抛出不要重复提交
                throw new UserException("user.repeat.submit", null);
            }
            redisCache.setCacheObject(key, key, localLock.time(), TIME_UNIT);
        }
        // 此处执行原方法 可能会有异常,切记万万不可捕获,否则将导致统一异常捕获失效
        return pjp.proceed();
    }

    /**
     * key的生成策略
     * @param keyExpress 注解key值
     * @param args 方法参数
     * @return 生成的缓存的key
     */
    private String getKey(String keyExpress, Object[] args) {
        for (int i = 0; i < args.length; i++) {
            keyExpress = keyExpress.replace("arg[" + i + "]", args[i].toString());
        }
        return keyExpress;
    }
}
上一篇:自定义注解实现Redis缓存


下一篇:谁有115网盘资源