当前位置: 正能量 » 代码编程 » Java » Spring自定义Aop实现锁机制

Spring自定义Aop实现锁机制

声明式锁(基于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注解控制切面执行顺序
  • 添加监控埋点记录锁竞争耗时
未经允许不得转载:正能量 » Spring自定义Aop实现锁机制

相关文章

评论 (0)

3 + 6 =