spring boot 自定义注解 实现本地锁

技术点

  1. AOP
  2. 注解声明
  3. 自动配置

声明注解

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LocalLock {
    String key() default "";
}

key为锁标识

AOP 实现注解

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.guodun.aiosign.tools.lock.LocalLock;
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.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

@Aspect
@Configuration
@Slf4j
public class LocalLockInterceptor {
    private static Cache<String, String> lockCache = CacheUtil.newLFUCache(200, DateUnit.SECOND.getMillis() * 10);
    @Around("@annotation(com.guodun.aiosign.tools.lock.LocalLock)")
    public Object interceptor(ProceedingJoinPoint pjp) {
        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)) {
            if (lockCache.containsKey(key)) {
                log.debug("发生死锁 : {} ",key);
                checkLock(key);
            }else {
                lockCache.put(key, key);
            }
        }
        try {
            return pjp.proceed();
        } catch (Throwable throwable) {
            throw new RuntimeException("服务器异常");
        } finally {
            // 请求结束后解除锁
           if (!StringUtils.isEmpty(key)) lockCache.remove(key);
        }
    }
    private void checkLock(String key)  {
        try {
            for (int i = 0; i < 20; i++) {
                if (!lockCache.containsKey(key)) return;
                Thread.sleep(500);
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (lockCache.containsKey(key))  throw new RuntimeException("请勿重复请求");
    }
    private String getKey(String keyExpress, Object[] args) {
        String[] keys = StrUtil.splitToArray(keyExpress,'.');
        log.debug("参数 {} ", JSON.toJSONString(keys));
        if (keys.length>0&&args.length>0){
            String args_str = keys[0];
            if(!NumberUtil.isInteger(args_str)) return null;
            int args_index = Integer.valueOf(args_str);
            if (args_index>args.length)return null;
            if(keys.length<2) {
                log.info("value  : {} ",args[args_index-1].toString());
                return args[args_index-1].toString();
            }
            Object value = ReflectUtil.getFieldValue(args[args_index-1],keys[1]);
            log.info("value  : {} ",value.toString());
            return value.toString();
        }
        return null;
    }
}

自动配置(spring boot)

在这里插入图片描述

#配置自定义Starter的自动化配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.keepgoon.tools.lock.local.LocalLockInterceptor
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页