添加方法级 Caller 锁

This commit is contained in:
2025-05-15 01:39:54 +08:00
parent fc9553f2db
commit e0e7942412
12 changed files with 430 additions and 25 deletions

View File

@@ -0,0 +1,54 @@
package quant.rich.emoney.component;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.*;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import quant.rich.emoney.util.CallerLockUtil;
import java.lang.reflect.Method;
import java.util.concurrent.locks.ReentrantLock;
@Aspect
@Component
public class CallerLockAspect {
private final SpelExpressionParser parser = new SpelExpressionParser();
@Around("@annotation(com.example.lock.LockByCaller)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
LockByCaller annotation = method.getAnnotation(LockByCaller.class);
// 获取 SpEL key如果有
Object[] args = pjp.getArgs();
String[] paramNames = signature.getParameterNames();
Object[] extraKey = new Object[0];
if (!annotation.key().isEmpty()) {
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < paramNames.length; i++) {
context.setVariable(paramNames[i], args[i]);
}
Expression expression = parser.parseExpression(annotation.key());
Object value = expression.getValue(context);
extraKey = (value == null) ? new Object[0] : new Object[]{value};
}
// 复用工具类的锁逻辑
ReentrantLock lock = CallerLockUtil.acquireLock(extraKey);
lock.lock();
try {
return pjp.proceed();
} finally {
lock.unlock();
}
}
}

View File

@@ -0,0 +1,20 @@
package quant.rich.emoney.component;
import java.lang.annotation.*;
/**
* 在方法上添加此注解,可针对调用方加锁,即:<br>
* 调用方法为 A 的,多次从 A 调用则加锁,从 B 调用时不受影响<br>
* 需要开启 AOP在任意配置类上增加注解<i><code>@EnableAspectJAutoProxy</code></i>
* @see CallerLockAspect
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LockByCaller {
/**
* 可选参数,用于 SpEL 表达式获取 key
* 例如:@LockByCaller(key = "#userId")
*/
String key() default "";
}