sentinel限流降级异常链降级需用@sentinelresource的fallback方法接收throwable参数或全局sentinelblockexceptionhandler处理器,二者均能获取完整异常链用于日志、监控与决策。

在 Spring Cloud Alibaba Sentinel 中,限流规则触发时默认抛出 BlockException(如 FlowException、DegradeException 等),它本身不继承自 RuntimeException,而是 Sentinel 自定义的受检异常基类。要实现“用异常链降级”,核心是:**让业务方法在被 Sentinel 保护时,一旦触发限流/降级,自动跳转到你指定的 fallback 方法,并且能拿到原始异常(含异常链)用于日志、监控或决策**。
1. 使用 @SentinelResource 注解 + fallback + exceptionsToIgnore
这是最直接支持异常链传递的方式。关键点在于:fallback 方法必须与原方法签名兼容(参数一致 + 返回值一致),且需显式声明接收 Throwable 参数。
- 原方法不抛出
BlockException(Sentinel 不强制检查,但建议不 throws) - fallback 方法第 1 个参数为
Throwable e,后续参数与原方法一致(顺序、类型完全相同) - 通过
exceptionsToIgnore明确排除你不希望触发 fallback 的异常(比如你已自己处理的业务异常)
示例:
@SentinelResource(
value = "queryUser",
fallback = "queryUserFallback",
exceptionsToIgnore = { IllegalArgumentException.class }
)
public User queryUser(Long userId) {
// 正常业务逻辑,可能触发限流
return userService.getById(userId);
}
// fallback 方法:第一个参数必须是 Throwable,后面跟原方法所有参数
public User queryUserFallback(Throwable e, Long userId) {
// ✅ 此时 e 就是 FlowException / DegradeException,可获取 cause 链
log.warn("queryUser 被 Sentinel 降级,异常={}", e.toString(), e);
if (e.getCause() != null) {
log.debug("原始根因:", e.getCause());
}
return User.defaultUser(); // 降级返回兜底数据
}
2. 全局 fallback 处理器(统一捕获 BlockException 链)
若不想每个方法都写 fallback,可用 SentinelBlockExceptionHandler 注册全局处理器,它接收 HttpServletRequest、HttpServletResponse 和 BlockException —— 注意:这里传入的是原始 BlockException,天然携带完整异常链(比如 DegradeException 的 cause 可能是 TimeoutException)。
- 实现
SentinelBlockExceptionHandler接口 - 在
handle方法中,可对e调用getCause()、getSuppressed()等获取完整异常链 - 适合统一记录、告警、或返回标准化降级响应(如 JSON 错误体)
示例:
@Component
public class GlobalBlockExceptionHandler implements SentinelBlockExceptionHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
BlockException e) throws Exception {
// ✅ e 就是原始 BlockException,可递归打印整个链
log.error("全局 Sentinel 限流/降级触发", e);
// 打印完整异常链(含 cause)
Throwable root = e;
int depth = 0;
while (root != null && depth
<h3>3. 自定义 BlockException 处理器 + 异常包装(进阶控制)</h3>
<p>如果需要把 <code>BlockException</code> 转成你自己的业务异常(如 <code>ServiceUnavailableException</code>),同时保留原始异常链,推荐用「异常包装」方式:</p>
- 注册
BlockExceptionHandler(非 Web 场景)或SentinelBlockExceptionHandler(Web 场景) - 在 handler 中 new 一个自定义异常,并把
e作为 cause 传入构造函数 - 这样调用栈里就保留了完整的原始 Sentinel 异常链
示例(Web 场景):
public class GlobalBlockExceptionHandler implements SentinelBlockExceptionHandler {
@Override
public void handle(HttpServletRequest req, HttpServletResponse resp, BlockException e) throws Exception {
// ✅ 包装成业务异常,保留原始链
throw new ServiceUnavailableException("资源受限", e);
}
}
// 自定义异常(继承 RuntimeException,方便传播)
public class ServiceUnavailableException extends RuntimeException {
public ServiceUnavailableException(String message, Throwable cause) {
super(message, cause); // ⚠️ 关键:传入 cause,链就保留了
}
}
这样下游 catch ServiceUnavailableException 时,调用 e.getCause() 仍能得到 FlowException 或 DegradeException,再继续 getCause() 就能拿到更底层原因(如 RPC 超时、DB 连接池耗尽等)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











