背景条件:
默认情况下sentinel发生限流或熔断是直接抛出异常BlockException然后在浏览器响应这么一句话
可见DefaultBlockExceptionHandler类源码
但在现在的前后端分离开发中,我们一般都会
统一响应格式
,因此这样的返回结果往往是不能满足我们的需求的,因此我们需要自定义sentinel熔断或降级的处理方式
这是我们就需要用到
@SentinelResource
注解
注,默认情况下sentinel只会将controller中的接口作为资源,而Service等其他地方的方法sentinel将不会作为sentinel的资源,我们可以手动在方法上加上@SentinelResource注解将其标注为sentinel的资源
前置知识:
BlockException类,其包含五个子类,分别对应sentinel流控降级规则的授权规则、降级规则、限流规则、热点规则、系统规则 因此
blockHandler()
是专门用来处理
sentinel异常
的
@SentinelResource注解常用属性介绍
使用方法及注意事项:
一
.
blockHandler():
使用blockHandler()指定指定发生blockExcption时的处理方法
@GetMapping("/hello/{id}")
@SentinelResource(value = "hello",blockHandler = "blockHandlerMethod")
public Result<String> hello(@PathVariable("id") String id){
testService.test();
return new Result<>(200,"操作成功","hello"+id);
}
public Result<String> blockHandlerMethod(String id, BlockException e){
if (e instanceof DegradeException){
return new Result<>(10000,"操作失败","服务已被降级或熔断");
}else if(e instanceof FlowException){
return new Result<>(10000,"操作失败","服务已被限流");
}else { //可以继续根据blockException的类型,配置对应的返回对象
return new Result<>();
}
}
效果:
限流
降级
使用注意事项:
1.处理方法必须与受保护资源在同一个类中
2.处理方法的修饰符必须为pulbic
3.处理方法的参数列表必须和受保护资源相同,并在最后
加上BlockException e接收异常
4.处理方法的返回值必须和受保护资源相同
二.blockHandlerClass
单独新建一个类用于处理受保护资源的BlockException,相比blockHandler()指定本类中的方法更加的解耦且灵活
使用方法:
处理类及处理方法
public class MyBlockExceptionHandler {
public static Result<String> blockExceptionHandler(String id, BlockException e) {
if (e instanceof DegradeException){
return new Result<>(10000,"操作失败","服务已被降级或熔断---byBlockHandlerClass");
}else if(e instanceof FlowException){
return new Result<>(10000,"操作失败","服务已被限流---byBlockHandlerClass");
}else { //可以继续根据blockException的类型配置对应的返回对象
return new Result<>(1000,"操作失败","其他类型的BlockException---byBlockHandlerClass");
}
}
}
受保护资源上配合
blockHandlerClass(指定处理方法所在的类)
及
blockHandler(指定处理方法的名字)
两个属性使用
@GetMapping("/hello/{id}")
@SentinelResource(value = "hello",blockHandlerClass ={MyBlockExceptionHandler.class},
blockHandler = "blockExceptionHandler")
public Result<String> hello(@PathVariable("id") String id){
return new Result<>(200,"操作成功","hello"+id);
}
效果
限流(流控就不展示了)
使用注意事项:
1.指定处理方法必须是public static的
2.处理方法参数列表及返回值和 blockHandler相同
三、fallback()
注意fallback和blockHandler的区别
1. blockHandler是专门(只)处理sentinel流控降级规则抛出的BlockException
2. 而fallback默认处理所有的异常,其中包括BlockEcxeption(因为BlockException是Exception的子类),也就是说如果我们不配置blockHandler,其抛出BlockEcxeption也将会进入fallback方法中
3. fallback处理的异常可通过@SentinelResource中的exceptionsToIgnore属性排除(
不知道为什么我测试可以排除ArithmeticException,但是排除不了BlockException
)
4. 如果同时配置了blockHandler和fallback,出现BlockException时将进入BlockHandler方法中处理
示例:为hello资源配置一个fallback方法打印异常类名,并留下一个除0异常
@GetMapping("/hello/{num}")
@SentinelResource(value = "hello",fallback = "fallbackMethod")
public Result<String> hello(@PathVariable("num") Integer num){
int result = 100/num;
return new Result<>(200,"操作成功","hello"+result);
}
public Result<String> fallbackMethod (Integer num,Throwable e){
return new Result<>(10000,"操作失败","出现"+e.getClass().getSimpleName()+"异常,进入指定的fallback方法");
}
当我们参数输入0,抛出除0异常
当我们为hello资源进行限流,触发BlockException异常,可以看到依旧会进入我们的fallback方法
使用注意事项:
1.方法必须和被保护资源处于同一个类
2.方法参数列表和受保护资源一致(
可选
是否在最后添加一个Throwable类型参数接收异常,注意类型必须是Throwable)
3.方法返回值必须和受保护资源相同
四、
fallbackClass
该属性类似于上面介绍的
blockHandlerClass,也是为了实现灵活应用及解耦
新建fallback类及方法
public class MyFallbackHandler {
public static Result<String> fallbackMethod (Integer num, Throwable e){
return new Result<>(10000,"操作失败","出现"+e.getClass().getSimpleName()+"异常," +
" 进入指定的fallback方法--byMyFallBackClass");
}
}
配合fallback()属性指定位于其他类的fallback方法
@GetMapping("/hello/{num}")
@SentinelResource(value = "hello",fallbackClass = {MyFallbackHandler.class},fallback = "fallbackMethod")
public Result<String> hello(@PathVariable("num") Integer num){
int result = 100/num;
return new Result<>(200,"操作成功","hello"+result);
}
效果:
除0
限流
使用注意事项:
1.指定处理方法必须是public static的
2.处理方法参数列表及返回值等和 fallback相同
五、defaultFallback
使用方法和fallback相同,优先级低于fallback,同时配置fallback和defaultFallback时由fallback生效