首页 > 其他分享 >3种Sentinel自定义异常,你用过几种?

3种Sentinel自定义异常,你用过几种?

时间:2023-11-22 09:56:11浏览次数:33  
标签:自定义 几种 msg 限流 Sentinel import 异常

Spring Cloud Alibaba Sentinel 是目前主流并开源的流量控制和系统保护组件,它提供了强大的限流、熔断、热点限流、授权限流和系统保护及监控等功能。使用它可以轻松的保护我们微服务,在高并发环境下的正常运行。

那么,当程序触发了限流和熔断规则时,如何自定义返回的异常信息呢?这是我们接下来要解决的问题。

0.概述

Spring Cloud Alibaba Sentinel 有以下 3 种自定义异常的实现方式:

  1. 自定义局部异常
  2. 自定义(Sentinel)全局异常
  3. 自定义系统异常

以上这 3 种实现方式,都可以重新定义 Sentinel 的异常返回信息,它们的具体实现如下。

1.自定义局部异常

自定义局部异常是在使用 @SentinelResource 注解时,直接定义的 blockHandler 异常方法,如下代码所示:

@SentinelResource(value = "/user/getuser",
            blockHandler = "myBlockHandler")
@RequestMapping("getuser")
public String getUser(Integer uid) {
    return "User:" + uid;
}

/**
 * 定义限流/熔断等异常
 */
public String myBlockHandler(Integer uid, BlockException 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 = "没有权限访问";
    }
    return msg;
}

注意事项

在定义 blockHandler 方法时,需要注意以下 3 个问题:

  1. 自定义的 blockHandler 方法的返回值,必须要和原方法(使用 @SentinelResource 注解修饰的方法)的返回值保持一致。
  2. 自定义的 blockHandler 方法的参数必须和原方法参数保持一致。
  3. 自定义的 blockHandler 方法的方法参数中必须包含 BlockException 参数。

如果不满足以上事项中的任何一项,那么就不能正常匹配到自定义的 blockHandler 方法,并且程序也会报错。

2.自定义全局异常

自定义 Sentinel 全局异常需要实现 BlockExceptionHandler 类,并重写 handle 方法,如下代码所示:

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = HttpStatus.TOO_MANY_REQUESTS.value();
        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = HttpStatus.UNAUTHORIZED.value();
        }
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(status);
        response.getWriter().println("{\"msg\": " + msg + ", \"code\": " + status + "}");
    }
}

自定义 Sentinel 全局异常是在执行 Sentinel 控制台设置的限流和熔断异常时,执行的全局自定义异常方法。

但是,如果是程序中出现的 Sentinel 报错信息,例如使用热点限流时,因为要配合使用 @SentinelResource 注解时,此时只自定义了 value 属性,未定义局部 blockHandler 方法,此时系统就会报错,但这个时候并不会执行 Sentinel 全局自定义异常,而是程序报错,此时就需要使用系统自定义异常来重新定义异常信息了。

3.自定义系统异常

自定义系统异常需要新建一个异常类,并且使用 @RestControllerAdvice 注解修饰此类,并配合 @ExceptionHandler 注解来完成全局系统异常的获取和定义,具体实现代码如下:

import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;


@RestControllerAdvice
public class CustomExceptionHandler {

    /**
     * 限流全局异常
     */
    @ExceptionHandler(FlowException.class)
    public Map handlerFlowException(){
        return new HashMap(){{
            put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            put("msg", "被限流");
        }};
    }

    /**
     * 熔断全局异常
     */
    @ExceptionHandler(DegradeException.class)
    public Map handlerDegradeException(){
        return new HashMap(){{
            put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            put("msg", "被熔断");
        }};
    }

    /**
     * 热点限流异常
     */
    @ExceptionHandler(ParamFlowException.class)
    public Map handlerparamFlowException(){
        return new HashMap(){{
            put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            put("msg", "热点限流");
        }};
    }

    /**
     *  Sentinel 权限拦截全局异常
     */
    @ExceptionHandler(AuthorityException.class)
    @ResponseBody
    public Map handlerAuthorityException(){
        return new HashMap(){{
            put("code", HttpStatus.UNAUTHORIZED.value());
            put("msg", "暂无权限");
        }};
    }
}

此时,只要是系统中出现的 Sentinel 报错信息,都会被此方法所捕获,并通过自定义的代码完成自定义异常信息的返回。

小结

Sentinel 有 3 种自定义异常的实现:自定义局部异常、自定义(Sentinel)全局异常、自定义系统异常。自定义局部异常作用范围比较小,需要给每个资源单独设置才行;而自定义全局异常作用范围比较大,但如果是程序报错,也不会执行其方法,所以需要配合系统异常同时来完成自定义异常的返回。

PS:如果这 3 种自定义异常同时存在,那么它的执行优先级是:自定义局部异常 > 自定义全局异常 > 自定义系统异常。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

标签:自定义,几种,msg,限流,Sentinel,import,异常
From: https://www.cnblogs.com/vipstone/p/17848233.html

相关文章

  • 10、Redis哨兵(sentinel)【面试重点】
    一、是什么二、能干嘛三、怎么玩(案例演示实战步骤)1、RedisSentinel架构,前提说明2、案例步骤2.1sentinel.conf文件位置2.2重点参数项说明2.3本次案例哨兵sentinel文件通用配置2.4先启动一主二从3个redis实例,测试正常的主从复制以下是哨兵......
  • 几种常见的排序算法总结
    常见的几种排序算法排序算法有很多,比较常见的有:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序等。并不是所有的都需要会。本文只会对其中部分算法进行总结。冒泡排序冒泡排序是一种比较简单的排序方法。也比较好理解,但是......
  • css 水平垂直居中的几种方法
    水平垂直居中的几种方式记录一下容器内只有单一元素时居中的几种方式<divstyle="width:300px;height:300px"class="wrap"><divstyle="width:100px;height:100px"class="box"></div></div>1.容器flex,调整内部轴线.wrap{di......
  • monaco editor自定义代码解析和代码高亮颜色配置
    //目前使用到的关于解析配置exportconstlanguage={//是否区分大小写,true区分ignoreCase:false,//关键字keywords:['aaa','bbb'],//类型关键字typeKeywords:[],//代码解析配置格式为[正则表达式,对应的类型如(string,number,comment)]tokenizer:......
  • Django自定义接口
    一、在有默认(create、list、retrieve、update、destroy)接口时自定义接口classIterationsViewSet(MyModelViewSet):queryset=uc_iterations.objects.all().order_by('id')serializer_class=IterationsSerializerpagination_class=DIYPagination#配置自定......
  • ant design vue 1.x 和 3.x 自定义表单示例
    以下是项目中用到的自定义表单的写法,vue2vue3各记录一个。1.x(Forvue2)自定义表单的示例实现如下图的控件代码如下:import{Component,Prop,Vue,Watch}from'vue-property-decorator'import{Moment}from'moment'typeValue={left:Moment;right:Moment......
  • 创建自定义日志筛选器
    Windows的事件查看器中的日志包含了很多信息,但是系统自带的筛选器只能筛选固定的字段和内容。有时候想根据某个事件中的用户名或者IP筛选的时候就没办法了。此时需要创建自定义筛选器来实现。首先找到希望筛选的日志,调整成详细的XML视图。  这里面就有我们需要用到的字段信......
  • vue自定义指令按enter键触发事件
    directives:{enter:{bind(el,binding){document.addEventListener('keyup',(event)=>{if(event.keyCode===13){binding.value()}})}}},v-enter="search"......
  • Springboot自定义starter
    Springboot自定义sarter这里通过自定义mybatis的starter来简单进行分析理解步骤:创建dmybatis-spring-boot-autoconfigure模块,提供自动配置功能,并定义配置文件META-INF/spring/xxx.imports创建dmybatis-spring-boot-starter模块,在starter中引入自动配置模块创建项目:1......
  • Android系统开发 Android10版本自定义系统版本号
    前言  framework开发,此博客基于Android10版本,实现自定义系统版本号。找到修改位置需要修改的关键文件是buildinfo.sh搜索一下文件找到要改的目标文件这里建议将这个文件拷贝出来修改,各自的编译环境不同,拷贝或者传输文件的方式不同,这里各自发挥。下面是我在wsl里把文件拷......