RepeatSubmitAspect.java
5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package com.infoloop.tianting.aspect;
import com.infoloop.tianting.annotation.RepeatSubmit;
import com.infoloop.tianting.annotation.RequestKeyParam;
import com.infoloop.tianting.constant.CommonConstants;
import com.infoloop.tianting.context.LoginContextHolder;
import com.infoloop.tianting.exception.ClientEndExceptions;
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.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
@Aspect
@Configuration
@Order(1024)
@Slf4j
public class RepeatSubmitAspect {
private final RedissonClient redissonClient;
@Autowired
public RepeatSubmitAspect(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Around("execution(public * * (..)) && @annotation(com.infoloop.tianting.annotation.RepeatSubmit)")
public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable {
final var methodSignature = (MethodSignature) joinPoint.getSignature();
final var method = methodSignature.getMethod();
final var requestLock = method.getAnnotation(RepeatSubmit.class);
final var lockKey = getLockKey(joinPoint);
final var lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(requestLock.expire(), requestLock.timeUnit())) {
return joinPoint.proceed();
} else {
log.error("Failed to acquire lock for method: {}", method.getName());
throw ClientEndExceptions.ResourceLocked.build(requestLock.message());
}
} catch (InterruptedException e) {
log.error("Interrupted while trying to acquire lock for method: {}", method.getName(), e);
} finally {
if (lock.isHeldByCurrentThread() && requestLock.methodAutoUnlock()) {
lock.unlock();
}
}
return null;
}
/**
* 获取LockKey
*
* @param joinPoint 切入点
*/
public static String getLockKey(ProceedingJoinPoint joinPoint) {
//获取连接点的方法签名对象
final var methodSignature = (MethodSignature) joinPoint.getSignature();
//Method对象
final var method = methodSignature.getMethod();
//获取Method对象上的注解对象
final var requestLock = method.getAnnotation(RepeatSubmit.class);
//获取方法参数
final var args = joinPoint.getArgs();
//获取Method对象上所有的注解
final var parameters = method.getParameters();
final var sb = new StringBuilder();
for (var i = 0; i < parameters.length; i++) {
final var keyParam = parameters[i].getAnnotation(RequestKeyParam.class);
//如果属性不是RequestKeyParam注解,则不处理
if (keyParam == null) {
continue;
}
//如果属性是RequestKeyParam注解,则拼接 连接符 "& + RequestKeyParam"
if (!sb.isEmpty()) {
sb.append(requestLock.delimiter());
}
sb.append(args[i]);
}
//如果方法上没有加RequestKeyParam注解
if (!StringUtils.hasText((sb.toString()))) {
//获取方法上的多个注解(为什么是两层数组:因为第二层数组是只有一个元素的数组)
final var parameterAnnotations = method.getParameterAnnotations();
//循环注解
for (var i = 0; i < parameterAnnotations.length; i++) {
final var object = args[i];
//获取注解类中所有的属性字段
final var fields = object.getClass().getDeclaredFields();
for (var field : fields) {
//判断字段上是否有RequestKeyParam注解
final var annotation = field.getAnnotation(RequestKeyParam.class);
//如果没有,跳过
if (annotation == null) {
continue;
}
//如果有,设置Accessible为true(为true时可以使用反射访问私有变量,否则不能访问私有变量)
field.setAccessible(true);
//如果属性是RequestKeyParam注解,则拼接 连接符" & + RequestKeyParam"
if (!sb.isEmpty()) {
sb.append(requestLock.delimiter());
}
sb.append(ReflectionUtils.getField(field, object));
}
}
}
if (requestLock.isLockByLoginUser()) {
final var operatorId = LoginContextHolder.hasLogin() ? LoginContextHolder.getId() : null;
return requestLock.prefix() + (operatorId != null ? CommonConstants.COLON + operatorId : "") + (!sb.isEmpty() ? CommonConstants.UNDERLINE + sb : "");
} else {
return requestLock.prefix() + (!sb.isEmpty() ? CommonConstants.UNDERLINE + sb : "");
}
}
}