ratelimiter 默认不抛异常,需手动判断并转换为 toomanyrequestsexception;可通过封装工具方法统一处理限流逻辑与异常转换,该异常应继承 runtimeexception 并包含状态码 429。

在使用 RateLimiter(如 Guava 的 RateLimiter 或 Resilience4j 的 RateLimiter)时,它本身**不会主动抛出异常**——默认策略是阻塞等待或直接返回 false,需你手动判断并转换为业务异常(如 TooManyRequestsException)。关键在于:捕获限流失败信号后,用 throw 主动抛出自定义异常。
Guava RateLimiter:acquire() 阻塞 vs tryAcquire() 非阻塞
Guava 的 RateLimiter 默认不抛异常。若想触发 TooManyRequestsException,应优先使用 tryAcquire() 判断是否能获取许可:
- 成功获取:继续执行业务逻辑
-
获取失败(返回
false):立即throw new TooManyRequestsException("Rate limit exceeded")
示例:
if (!rateLimiter.tryAcquire(1, 0, TimeUnit.SECONDS)) { throw new TooManyRequestsException("Request rejected: rate limit exceeded"); } // 后续业务逻辑Resilience4j RateLimiter:监听拒绝事件并抛异常
Resilience4j 的 RateLimiter 支持注册 onFailure 回调,但它本身不中断执行流程。你需要配合装饰器(如 RateLimiter.decorateSupplier())+ 异常处理:
- 用
decorateSupplier包装业务逻辑 - 调用时若被限流,Resilience4j 会抛出
CallNotPermittedException - 在外层 catch 并转为
TooManyRequestsException
示例:
Supplier自定义 RateLimiter 包装器:统一异常转换
为避免重复判断,可封装一个工具方法,将限流逻辑与异常转换解耦:
- 接收
RateLimiter和业务Runnable/Supplier - 内部调用
tryAcquire,失败则 throwTooManyRequestsException - 成功则执行业务逻辑,原样返回结果或 void
这样所有限流点只需调用该工具,异常类型和消息保持一致。
注意 TooManyRequestsException 的设计
确保该异常继承自 RuntimeException(除非你明确需要检查异常),且建议包含标准 HTTP 状态码信息(如通过实现 ResponseStatusException 或添加 status 字段):
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











