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、设计模式、消息队列等模块。

3种Sentinel自定义异常,你用过几种?的更多相关文章

  1. 几种破解MySQL root密码的几种方法:

    几种破解MySQL root密码的几种方法: 方法一 使用phpmyadmin,这是最简单的了,修改mysql库的user表,不过别忘了使用PASSWord函数. 方法二 使用mysqladmin,这 ...

  2. 运算符关键字。数据区别大小写。日期范围。判空的两种写法。NOT IN的两种写法。IN范围可含NULL,但NOT IN值范围不能含NULL。

    比较:>,<,=,>=,<=,<>(!=) 逻辑:AND,OR,NOT 范围:BETWEEN...AND... 范围:IN,NOT IN 判空:IS NULL, I ...

  3. LVS(Linus Virtual Server):三种负载均衡方式比较+另三种负载均衡方式

    还有个姊妹篇也可以参考这个文章:六大Web负载均衡原理与实现 什么是LVS (Linux Virtual Server)?   首先简单介绍一下LVS (Linux Virtual Server)到底 ...

  4. Java反射获取class对象的三种方式,反射创建对象的两种方式

    Java反射获取class对象的三种方式,反射创建对象的两种方式 1.获取Class对象 在 Java API 中,提供了获取 Class 类对象的三种方法: 第一种,使用 Class.forName ...

  5. FMX有两种消息处理的实现方式,一种是用TMessageManager来实现自定义的消息,另外一种象TEdit中的实现,直接声明消息方法(firemonkey messaging)

    看FMX代码,发现有两种消息处理的实现方式,一种是用TMessageManager来实现自定义的消息,另外一种象TEdit中的实现,直接声明消息方法.   早前,看过文章说TMessageManage ...

  6. 【Java面试】Java有几种文件拷贝方式,哪一种效率最高?

    "Java有几种文件拷贝方式,哪一种效率最高?" 这个问题是京东一面的时候,针对4年经验的同学的一个面试题. 大家好,我是Mic,一个工作了14年的Java程序员. 关于这个问题的 ...

  7. 入口点函数的19种消息,AcRxArxApp只处理16种。

    AcRx::AppMsgCode一共有19种消息. 但由IMPLEMENT_ARX_ENTRYPOINT宏实现的App类,只处理了16种消息. 缺: kSuspendMsg = 16,    kIni ...

  8. Delphi一共封装(超类化)了8种Windows基础控件和17种复杂控件

    超类化源码: procedure TWinControl.CreateSubClass(var Params: TCreateParams; ControlClassName: PChar); con ...

  9. java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))

    Java提高篇--对象克隆(复制)(转自:http://www.cnblogs.com/Qian123/p/5710533.html#_label0)   阅读目录 为什么要克隆? 如何实现克隆 浅克 ...

  10. POI使用:用poi接口不区分xls/xlsx格式解析Excel文档(41种日期格式解析方法,5种公式结果类型解析方法,3种常用数值类型精度控制办法)

    一.使用poi解析excel文档 注:全部采用poi接口进行解析,不需要区分xls.xlsx格式,不需要判断文档类型. poi中的日期格式判断仅支持欧美日期习惯,对国内的日期格式并不支持判断,怎么办? ...

随机推荐

  1. node: #!/usr/bin/env node

    声明 windows中不支持Shebang,它是通过文件的扩展名来确定使用什么解释器来执行脚本 参考链接: https://juejin.cn/post/6844903826344902670

  2. asset module type 替代 loader 处理图片字体等文件资源

    前面文章中 体验了webpack的打包 .解析css资源 ,接下来看看项目中常用到的图片.字体.文件该怎么处理吧~ 项目路径如下,在上一篇 解析css资源 项目基础上增加了一些文件 demo ├─ s ...

  3. UI通过元素定位实现特定区域截图

    最近计划做一个自动截图的工具,目的是实现性能测试资源监控平台(grafana)各硬件资源的自动截图,解放手工操作.前期的截图做了如下探索. 1. 整个页面截图 1.1 代码实现 通过save_scre ...

  4. Linux服务器的性能监控与分析

    通过vmstat分析性能  如上图所示,我们在命令vmstat后面添加了两个参数,1表示间隔一秒获取一次,10表示总共获取10次 我们一列一列数据来看: r:代表目前实际运行的指令队列,很高表示CPU ...

  5. 【日常踩坑】解决 pip 安装第三方包时因 SSL 报错

    目录 踩坑 什么是 SSL ? 为什么会报错 解决办法 1. 临时关闭代理.VPN 或者网络抓包等软件 2. 通过镜像的 HTTP 源来避免 SSL 认证问题 3. 切换至低版本 pip 参考资料 踩 ...

  6. 【译】通过 GitHub Copilot Chat 简化代码优化和调试(AI 辅助编程)

    今年3月,我们宣布了 Visual Studio 2022 的 GitHub Copilot Chat.通过 Chat, Copilot 已经超越了代码补全,提供了对代码工作原理的深入分析和解释.它支 ...

  7. 【项目源码】基于JSP动漫论坛的设计与实现

    动漫论坛项目主要用于实现动漫爱好者的互相交流,基本功能包括:注册用户.登录.浏览帖子.发布新帖.回复帖子.等.本系统结构如下: (1)普通用户: 注册用户:如果用户为非会员用户,通过注册,经审核通过之 ...

  8. redhat7查找已接网线但是还未配置IP的网卡接口

    方法一:nmcli 输出中参数WIRED-PROPERTIES.CARRIER为on即为接网线网卡 #nmcli device show |grep -i -E "device|carrie ...

  9. SQL注入简介

    SQL注入(SQL Injection)是一种计算机安全漏洞,它允许攻击者通过操纵应用程序的输入来执行恶意的SQL查询,从而访问.修改或删除数据库中的数据.这种攻击通常发生在应用程序未正确验证.过滤或 ...

  10. springboot、jvm调优(设置运行的参数)

    1.工具 jdk自带的工具位置: 找到窗口->应用程序 2.问题和方式 在SpringBoot项目中,调优主要通过配置文件和配置JVM的参数的方式进行. 2.1 springboot修改配置文件 ...