声明式锁(基于Spring AOP)
通过自定义注解和AOP统一管理锁逻辑,类似@Transactional。
(1) 定义锁注解
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConcurrentLock {
/**
* 锁的Key(支持SpEL表达式,如 #orderId)
*/
String key() default "";
/**
* 获取锁超时时间
*/
long timeout() default 5;
/**
* 时间单位
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
(2) 实现AOP切面
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.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@Aspect
@Component
public class LockAspect {
// 使用可重入锁(实际项目中可替换为分布式锁)
private final Lock lock = new ReentrantLock();
// SpEL表达式解析器
private final ExpressionParser parser = new SpelExpressionParser();
@Around("@annotation(concurrentLock)")
public Object around(ProceedingJoinPoint joinPoint, ConcurrentLock concurrentLock) throws Throwable {
String lockKey = resolveLockKey(joinPoint, concurrentLock);
try {
// 尝试获取锁(带超时)
if (lock.tryLock(concurrentLock.timeout(), concurrentLock.timeUnit())) {
return joinPoint.proceed();
} else {
throw new RuntimeException("[" + lockKey + "] Acquire lock failed after "
+ concurrentLock.timeout() + " " + concurrentLock.timeUnit());
}
} finally {
if (((ReentrantLock) lock).isHeldByCurrentThread()) {
lock.unlock();
}
}
}
/**
* 解析锁的Key(支持SpEL表达式)
*/
private String resolveLockKey(ProceedingJoinPoint joinPoint, ConcurrentLock concurrentLock) {
// 获取方法参数名和值
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Object[] args = joinPoint.getArgs();
String[] paramNames = signature.getParameterNames();
// 创建评估上下文
StandardEvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < args.length; i++) {
context.setVariable(paramNames[i], args[i]);
}
// 解析SpEL表达式
Expression expression = parser.parseExpression(concurrentLock.key());
String dynamicKey = expression.getValue(context, String.class);
return method.getDeclaringClass().getName()
+ ":"
+ method.getName()
+ ":"
+ dynamicKey;
}
}
(3) 在Service中使用
@Service
public class OrderService {
// 使用SpEL动态生成锁Key
@ConcurrentLock(key = "'order:' + #orderId", timeout = 3)
public void processOrder(String orderId, int quantity) {
// 需要同步的业务逻辑
System.out.println("Processing order: " + orderId);
}
// 静态Key示例
@ConcurrentLock(key = "GLOBAL_CONFIG_LOCK")
public void updateGlobalConfig() {
// 全局配置更新
}
}
关键实现说明
SpEL动态Key解析:
-
使用StandardEvaluationContext绑定方法参数
-
支持形如#orderId的表达式,自动替换为实际参数值
-
示例方法processOrder生成的Key:com.example.OrderService:processOrder:order:123
锁管理增强:
-
检查当前线程是否持有锁后再释放(避免IllegalMonitorStateException)
-
支持自定义超时时间和时间单位
-
完整的异常处理流程
扩展建议:
// 若要升级为分布式锁,只需替换Lock实现:
@Autowired
private RedissonClient redissonClient;
private Lock getDistributedLock(String lockKey) {
return redissonClient.getLock(lockKey);
}
性能优化:
- 添加@ConditionalOnProperty控制锁功能的开关
- 添加@Order注解控制切面执行顺序
- 添加监控埋点记录锁竞争耗时