【Java】Sentinel自定义异常和全局异常处理器

注:本文章全由自己想法尝试和记录,若有不对或者考虑不完全的情况是十分正常的,有意见请留言,无任何恶意引导

Sentinel中各种流控,熔断,授权当被拦截的时候,都是统一返回一个异常

Blocked by Sentinel (flow limiting)

(这是只设置流控的情况下)

【Java】Sentinel自定义异常和全局异常处理器_第1张图片

【Java】Sentinel自定义异常和全局异常处理器_第2张图片

(这是只设置了授权规则的情况下)

【Java】Sentinel自定义异常和全局异常处理器_第3张图片【Java】Sentinel自定义异常和全局异常处理器_第4张图片

当然 这个返回结果自然对用户来说是体验不好的  因为用户不懂得到底出了什么问题  他的一切返回值都是Blocked by Sentinel (flow limiting)  ------>被Sentinel限流拦截   不仅不是返回正确的限制原因,也不符合我们的返回结果格式的统一

所以 为了解决这个问题 Sentinel中存在一个让我们自定义异常返回的方式:

实现BlocakExceptionHandler接口即可     接口中有个方法

void handle(HttpServletRequest request,HttpSwervletResponse response,BlockException e) throws Exception;

通过实现该方法 可以接收所有的来自Sentinel的所有异常BlockException e 然后我们可以通过对该异常进行判断  判断是限流还是降级还是授权拦截
然后我们通过对方法参数 HttpServletResponse response对返回值进行自定义设置

可以看到,该方法的实质可以理解为捕获拦截了BlockException 然后再对返回值进行设置

那么 该异常的捕获逻辑 能通过Spring提供的全局异常处理器来捕获和处理吗?

为了检验 我们来测试测试:

首先 准备一个简单的微服务项目逻辑,我们先使用Sentinel提供的自定义异常结果的方式:

@Component  //  注册为Bean  让Spring管理
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = 429;

// 通过判断异常的类型 来判断到底是限流还是熔断降级还是授权限制
        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = 401;
        }

        response.setContentType("application/json;charset=utf-8");
        response.setStatus(status);
        response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}Sentinel自定义异常");
    }
}

【Java】Sentinel自定义异常和全局异常处理器_第5张图片

重启服务 然后我们给/order/{orderId}依次单独添加限流和权限规则,再次访问查看页面返回

可以发现,均被拦截,而且返回信息很好,是我们的自定义形式(上面为限流 下面为授权)

【Java】Sentinel自定义异常和全局异常处理器_第6张图片

然后我们再来看看使用Spring提供的全局异常处理器进行捕获处理

先将刚刚定义的Sentinel的自定义异常类的@Component注解去掉 使其不会被注册从而不生效

【Java】Sentinel自定义异常和全局异常处理器_第7张图片

然后我们定义Spring的全局异常处理器:定义方法如下

/*
全局异常处理器的定义:

定义一个类  并且带有@RestControllerAdvice注解

@ExceptionHandler注解指定要捕获的异常的类型
*/


@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler(Exception.class)
    public String globalException(Exception e){
        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 = "没有权限访问";
        }
        msg+="   全局异常处理器判断得到";
        return msg;
    }
}

【Java】Sentinel自定义异常和全局异常处理器_第8张图片

然后我们重启动服务  再次分别设置限流和权限规则 取访问查看异常返回

却发现  无论是限流还是授权  成功被拦截了 但是没有按照哦我们想要的进行返回

然后我们对程序设置断点 调式的方式再次运行  发现该异常更不没有被捕获到  断点处根本没有走到

但是我们手动抛一个异常  确实被捕获到了 那么说明我们的全局异常处理器在定义和配置上是没问题的  而且这个返回是要大于压制Sentinel的默认异常返回的

【Java】Sentinel自定义异常和全局异常处理器_第9张图片

【Java】Sentinel自定义异常和全局异常处理器_第10张图片

那么现在还有一种可能的情况  就是BlockException类并不是Exception的子类 不是基于Exception父类进行定义的。因为我们的全局异常处理器是捕获Exception及其子类 ,但现在没有被捕获,所以我们有理由猜测这一种情况

要验证这个想法,我们对全局异常处理器进行一下修改即可  即 将捕获的异常类型指定为BlockException就可以的

【Java】Sentinel自定义异常和全局异常处理器_第11张图片

最后 我们再次尝试 得到的结果还是Sentinel的通用异常返回

而且断点处依旧没有任何的反应

【Java】Sentinel自定义异常和全局异常处理器_第12张图片

所以 最终我们的到的结论是-----Sentinel的异常处理管理不能使用Spring的全局异常处理器进行捕获和处理

你可能感兴趣的:(sentinel)