spring boot 自定义注解 实现本地锁
技术点
- AOP
- 注解声明
- 自动配置
声明注解
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
还没有评论,来说两句吧...