resilience4j默认对runtimeexception记为失败,但需自定义recordfailurepredicate区分业务异常(如businessexception)与系统异常(如timeoutexception);支持递归检查root cause,并注意fallback触发与熔断统计无关。

Resilience4j 默认只对 受检异常(Checked Exception)不触发熔断,而对 非受检异常(Unchecked Exception,即 RuntimeException 及其子类)默认会统计为失败,从而可能触发熔断。但实际使用中,你可能希望:某些 RuntimeException(比如业务自定义的 BusinessException)**不视为错误**,不计入失败率;而另一些(如 NullPointerException、TimeoutException)才需要熔断。这就需要显式配置“哪些异常该忽略、哪些该记录为失败”。
1. 明确异常分类策略
Resilience4j 的熔断器(CircuitBreaker)通过 recordFailurePredicate 判断是否将一次执行标记为“失败”。默认行为是:只要抛出 RuntimeException 或 Error 就记为失败,Exception(受检异常)则忽略——但这只是默认值,**可完全自定义**。
你需要决定:
- 哪些 RuntimeException 是“预期中的业务异常”,不该影响熔断(例如
OrderAlreadyExistsException) - 哪些是“系统性异常”,必须触发熔断(例如
HttpClientErrorException、SocketTimeoutException) - 是否要排除特定异常的 cause 链(比如外层是 RuntimeException,但根本原因是 IOException)
2. 自定义 recordFailurePredicate
在构建 CircuitBreaker 时,用 CircuitBreakerConfig.custom() 设置判断逻辑:
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // 失败率阈值
.waitDurationInOpenState(Duration.ofSeconds(60))
.ringBufferSizeInHalfOpenState(10)
.ringBufferSizeInClosedState(100)
// 关键:只把指定异常视为失败
.recordFailurePredicate(throwable -> {
// 排除业务异常:不熔断
if (throwable instanceof BusinessException ||
throwable instanceof ValidationException) {
return false;
}
// 其他 RuntimeException 和 Error 都算失败
return throwable instanceof RuntimeException || throwable instanceof Error;
})
.build();
注意:recordFailurePredicate 返回 true 表示“记为失败”,false 表示“忽略该异常,不计入失败统计”。
3. 处理嵌套异常(getCause 链)
有时异常被包装过(如 ExecutionException 包着 TimeoutException),需递归检查 root cause:
.recordFailurePredicate(throwable -> {
Throwable root = ThrowableUtils.getRootCause(throwable);
if (root instanceof TimeoutException ||
root instanceof ConnectException) {
return true; // 触发熔断
}
if (root instanceof BusinessException) {
return false; // 忽略
}
return throwable instanceof RuntimeException || throwable instanceof Error;
})
其中 ThrowableUtils.getRootCause() 可自行实现(循环调用 getCause() 直到为 null)。
4. 降级方法(fallback)与异常类型无关
Resilience4j 的 fallback(如 decorateSupplier(...).withFallback(...))**只要执行失败(无论是否被熔断器统计为失败)且未被 catch,就会触发**。但要注意:
- 如果异常被
recordFailurePredicate判定为 false(不记失败),它仍会传播出去 → 若没被 try-catch,fallback 依然会执行 - 若你在业务代码里已捕获并处理了
BusinessException,那它根本不会到达 Resilience4j,自然也不走 fallback - 真正需要 fallback 的,通常是那些你 无法在调用前预判、又不想让上游看到原始异常 的场景(如远程调用超时、服务不可用)
所以 fallback 的设计重点不在“区分异常类型”,而在于提供稳定、有意义的兜底响应(如返回缓存数据、默认值或友好提示)。
不复杂但容易忽略:默认行为不是万能的,尤其在混合使用多种 RuntimeException 的微服务中,务必显式声明失败判定逻辑,否则熔断可能过早打开,或该熔断时不熔断。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











