在微服务开发中,流量控制是保障系统稳定性的重要手段,Sentinel 作为一款强大的流量控制框架被广泛使用。本文将探讨在使用 @SentinelResource
注解时,限流不走自定义 ExceptionHandler
的问题及解决方案。
一、问题背景
在我们的应用中,使用了 Sentinel 进行流量控制,并且定义了一个自定义的异常处理器 MyExceptionHandler
来处理 BlockException
。然而,在实际测试中发现,当发生限流时,自定义的异常处理器并没有被触发。
二、相关代码及分析
(一)自定义异常处理器 MyExceptionHandler
java
@Component
public class MyExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
String msg ="";
if (e instanceof FlowException){
msg = "手速太快了,慢点";
}else if (e instanceof ParamFlowException){
msg="数据太热";
}else if (e instanceof DegradeException){
msg = "走降级";
} else if (e instanceof AuthorityException) {
msg = "级别不够";
}else {
msg = "被系统制裁了";
}
httpServletResponse.setContentType("text/html;charset=utf-8");
httpServletResponse.getWriter().println(msg);
}
}
这个处理器实现了 BlockExceptionHandler
接口,理论上应该能处理各种 BlockException
相关的异常。
(二)Sentinel 资源注解及异常处理流程
- 资源定义
java
@SentinelResource(value = "register",blockHandler ="handleBlock")
在方法上添加了 @SentinelResource
注解,并指定了 blockHandler
方法。
- 全局异常处理器
java
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理异常
@ExceptionHandler(BlockException.class) //指定能够处理的异常类型
public R ex(BlockException e){
e.printStackTrace();//打印堆栈中的异常信息
//捕获到异常之后,响应一个标准的Result
return R.error("对不起,操作失败,请联系管理员666");
}
@ExceptionHandler(Exception.class) //指定能够处理的异常类型
public R ex(Exception e){
e.printStackTrace();//打印堆栈中的异常信息
//捕获到异常之后,响应一个标准的Result
return R.error("对不起,操作失败,请联系管理员888");
}
}
定义了全局异常处理器,用于处理 BlockException
和其他通用异常。
(三)异常处理流程分析
当在方法上添加 @SentinelResource
注解时,Sentinel 会通过 AOP 拦截方法调用,并在内部处理限流 / 降级逻辑。此时:
- 如果指定了
blockHandler
,会优先调用该方法。 - 如果未指定
blockHandler
,Sentinel 默认会将BlockException
重新抛出,而不是交给BlockExceptionHandler
处理。
这就是为什么自定义的全局 MyExceptionHandler
没有被触发的原因。
三、解决方案
如果想要自定义的异常处理器生效,可以考虑以下两种方式:
- 移除
blockHandler
指定:如果不需要特殊的blockHandler
处理逻辑,可以移除@SentinelResource
注解中的blockHandler
属性,这样异常会按照正常的BlockExceptionHandler
流程进行处理。 - 在
blockHandler
中手动调用自定义异常处理逻辑:在blockHandler
方法中,手动调用自定义异常处理器的逻辑,以实现更灵活的异常处理。
四、总结
通过本文的分析,我们了解了 @SentinelResource
注解在异常处理方面的机制,以及为什么自定义的 ExceptionHandler
可能不会被触发。在实际开发中,我们需要根据具体的业务需求,合理配置和使用 Sentinel 的异常处理机制,以确保系统的稳定性和健壮性。
希望本文能对大家在使用 Sentinel 进行流量控制和异常处理时有所帮助。如果你有任何疑问或建议,欢迎在评论区留言交流。