一个基于 Redisson 实现分布式锁的库存 AOP 切面处理逻辑

一个基于 Redisson 实现分布式锁的库存扣减场景,包含了具体的业务接口和对应的 AOP 切面处理逻辑

🛒 库存扣减业务接口

该接口演示了如何利用自定义注解 @RedissonLock 实现分布式锁,并包含库存检查、模拟耗时操作、幂等性校验及库存扣减逻辑。

/**
库存扣减
@param stockDeductDto
@return
*/
@PostMapping(value = "/test/deduct/stock")
@ResponseBody
@RedissonLock(key = "'lock:' + #stockDeductDto.transactionId", fairLock = true)
public Result deductStock(@RequestBody StockDeductDto stockDeductDto) {

int deductStock = stockDeductDto.getDeductStock();

// 1. 库存预检查
if (deductStock > inventory.get()) {
return Result.failure("库存不足");
}

// 2. 模拟业务处理耗时 (等待5s)
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}

// 3. 幂等性判断:检查 transactionMap 是否已存在 transactionId
Integer status = trxMap.get(stockDeductDto.getTransactionId());

// 状态 2:已回滚处理
if (status != null && status == 2) {
return Result.successWithErrorCode(
ResultStatus.Already_Processed.code + "",
ResultStatus.Already_Processed.name,
"已回滚处理,无法再操作"
);
}

// 状态 1:已处理
if (status != null && status == 1) {
return Result.successWithErrorCode(
ResultStatus.Already_Processed.code + "",
ResultStatus.Already_Processed.name,
"已处理,无法再操作"
);
}

// 4. 执行扣减
inventory.addAndGet(-deductStock);
trxMap.put(stockDeductDto.getTransactionId(), 1);

log.info("库存扣减成功,TransactionId:{}", stockDeductDto.getTransactionId());
return Result.success();
}

🔒 Redisson 分布式锁切面实现

该切面类负责拦截带有 @RedissonLock 注解的方法,解析 SpEL 表达式生成锁键,并处理锁的获取(包括公平锁和等待超时机制)与释放。

import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class RedissonLockAspect {

@Autowired
private RedissonLockerUtil redissonLockerUtil;

/**
环绕通知:处理分布式锁逻辑
*/
@Around("@annotation(redissonLock)")
public Object around(ProceedingJoinPoint joinPoint, RedissonLock redissonLock) throws Throwable {
String lockKey = parseSpel(redissonLock.key(), joinPoint); // 解析 SpEL 表达式
long waitTime = redissonLock.waitTime();
long leaseTime = redissonLock.leaseTime();
boolean fairLock = redissonLock.fairLock();
RLock lock = null;

try {
// 尝试获取锁逻辑
if (waitTime > 0) {
// 带超时时间的尝试获取锁
lock = redissonLockerUtil.tryLock(lockKey, TimeUnit.SECONDS, waitTime, leaseTime);
if (lock == null) {
return Result.failure("系统繁忙,请稍后再试");
}
} else {
// 无限等待排队锁 (公平锁/非公平锁)
log.info("尝试获取无限等待排队锁,key: {}", lockKey);
lock = fairLock ? redissonLockerUtil.fairlock(lockKey) : redissonLockerUtil.lock(lockKey);
if (lock == null) {
log.warn("获取锁失败: {}", lockKey);
return Result.failure("系统繁忙,请稍后再试");
}
}

log.info("成功获取锁: {}", lockKey);

// 执行业务逻辑
return joinPoint.proceed();

} finally {
// 释放锁
if (lock != null) {
redissonLockerUtil.unlock(lock);
log.info("锁已释放: {}", lockKey);
}
}
}

/**
解析 SpEL 表达式
*/
private String parseSpel(String spel, ProceedingJoinPoint joinPoint) {
// 获取方法参数名和值
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String[] parameterNames = signature.getParameterNames();
Object[] args = joinPoint.getArgs();

// 构建 SpEL 上下文
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], args[i]);
}

// 解析并获取表达式值
ExpressionParser parser = new SpelExpressionParser();
return parser.parseExpression(spel).getValue(context, String.class);
}
}

posted @ 2026-04-12 22:47  cqs1234  阅读(18)  评论(0)    收藏  举报