一个基于 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);
}
}
浙公网安备 33010602011771号