分布式锁获取失败不属于业务异常,不应纳入全局异常处理器统一捕获;应分层处理:锁层返回状态结果,业务层语义化判断并执行重试、降级等策略,仅基础设施故障类锁异常才需全局兜底。

分布式锁获取失败本身不属于传统意义上的“业务异常”,而更接近资源竞争或系统协调问题,因此不建议直接归入全局异常处理器(如 @ControllerAdvice + @ExceptionHandler)统一捕获。盲目将其纳入全局异常处理,容易掩盖真实问题、干扰监控指标,甚至导致重试逻辑混乱。
为什么不能简单用全局异常捕获锁失败
• 锁获取失败是预期中的并发控制行为,不是程序缺陷,比如高并发下抢锁失败应走降级或重试,而非抛出 ServiceException 统一兜底
• 全局异常处理器通常面向 Controller 层,而分布式锁多在 Service 或 AOP 切面中获取,调用链路不在其作用域内
• 若强行包装成 RuntimeException 上抛,会绕过业务层对重试、等待、超时等策略的精细控制
推荐的分层处理方式
• 在锁封装层显式返回结果:使用类似 Redisson 的 tryLock(long waitTime, long leaseTime, TimeUnit unit) 方法,返回 boolean;或自定义 LockResult 类,含 success、timeout、interrupted 等状态字段
• 业务方法内做语义化判断:根据返回结果决定是重试、走缓存、返回提示,还是抛出特定业务异常(如 LockAcquireTimeoutException),再由对应 @ExceptionHandler 处理该定制异常
• 对可重试场景,交由框架级重试机制:如 Spring Retry 配合 @Retryable(value = LockAcquireFailedException.class, maxAttempts = 3),避免手动 while 循环
• 阻塞等待型锁失败,走线程唤醒+队列管理:例如 Redisson 的 RLock#tryLock() 返回 false 后,可登记到本地等待队列,由定时任务或发布订阅通知唤醒,不依赖异常流
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
需要全局兜底的极少数情况
• 当锁组件自身抛出非受检异常(如 Redis 连接中断导致 JedisConnectionException),这类属于基础设施故障,可被全局捕获并转为系统错误响应
• 自定义锁工具类中主动 throw new LockOperationException("Redis lock init failed"),且该异常继承 RuntimeException 并明确标记为需统一日志+告警的系统级锁异常
• 此时可在 @ControllerAdvice 中针对 LockOperationException 做记录、发告警、返回 500 或降级码,但不包含正常竞争失败
关键在于区分“锁没抢到”和“锁根本用不了”。前者是逻辑常态,后者才是异常事件。处理重心应放在锁调用前的参数校验、调用后的状态解析、以及失败后的策略编排,而不是塞进一个 catch-all 异常处理器里。










