一. 简单解释
- 在前面配置限流,熔断降级时,可以针对url 设置限流,或使用@SentinelResource 注解针对资源名称设置接口限流熔断降级等
- 出现的情况:
- 针对 Url 对接口设置限流熔断降级设置时,如果触发降级,再去请求接口,执行Sentinel默认降级方法抛出"Blocked by Sentinel (flow limiting)"信息
- 使用 @SentinelResource 设置资源名称,针对资源名称对接口设置限流熔断降级时,可以通过 @SentinelResource 中的 blockHandler 属性设置降级方法,当触发降级时执行该属性指向的降级方法,如果不添加该属性时,会通过 Sentinel 报错(该属性添加的降级方法是针对触发降级后执行的,如果方法执行抛出了异常,不会执行降级)
- 针对以上两种情况分析存在的问题:
- 降级时执行的是系统默认的降级方法,需要修改为自定义的,根据业务给出指导的降级返回
- 使用 @SentinelResource 的 blockHandler 添加降级方法,一个方法对应一个降级方法,并且业务代码,与降级代码耦合到在一块,需要解决耦合,与代码膨胀问题
二. @SentinelResource 注解详解
- @SentinelResource 注解中包含的属性
- value String类型,必填 资源名称
- entryType EntryType.OUT/IN 标记流量的方向
- blockHandler String 类型,指定当前使用@SentinelResource修饰的方法触发降级时执行的降级方法,方法名
- blockHandlerClass 与 blockHandler 注解配合使用,当 blockHandler 指定的降级方法与当前触发降级的方法不再同一个类中时,通过 blockHandlerClass 指向降级方法所在的类.class,但是在该类中 blockHandler 指定的方法必须是 static 类型否则无效
- fallback 当 @SentinelResource修饰的方法抛出异常时执行的降级方法
- fallbackClass 与 fallback 配合使用,当@SentinelResource修饰的方法发送异常时而 fallback 指定的降级方法与当前方法不再同一个类中,使用 fallbackClass 设置降级方法所在的类.class,注意点在该类中 fallback 指向的降级方法必须为 static 类型,否则无效
- defaultfallBack 通用的异常降级方法
- exceptionsToIgnore 在使用 fallback 指定当方法发生异常时执行的降级方法,但是某些情况下,方法发出异常我们并不想执行降级方法,通过该注解设置忽略哪些异常
exceptionsToTrace 需要 trace 的异常
com.alibaba.csp.sentinel.Suhu
com.alibaba.csp.sentinel.slots.block.flow.FlowRule
com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager
三. @SentinelResource 设置异常降级方法
- 通过 @SentinelResource 注解的 fallback 指定当前被该注解修饰的方法抛出异常时执行的降级方法
//当请求 /exceptionBlockTest 接口时,如果该接口发生异常,会自动执行下面的 exceptionMethod()降级方法
@GetMapping("/exceptionBlockTest")
@SentinelResource(value = "exceptionBlockTest", fallback = "exceptionMethod")
public String exceptionBlockTest(String str){
int i = 10/0;
return "方法正常执行";
}
//异常降级方法,返回值类型,形参列表要与实际方法一致
public String exceptionMethod(String str){
System.out.println("发送异常执行的降级方法,接收参数:"+str);
return "发送异常执行的降级方法,接收参数:"+str;
}
- 通过 @SentinelResource 的 fallback 设置了当方法发生异常后执行的降级方法,在某些情况下方法发生的某些指定异常我们并不想执行降级方法,通过该注解的 exceptionsToIgnore 属性忽略指定抛出的异常
//当请求 /exceptionBlockTest 接口时,如果该接口发生异常,会自动执行下面的 exceptionMethod()降级方法
//但是当该方法抛出异常类型为 MyException 时,忽略不会执行降级方法
@GetMapping("/exceptionBlockTest")
@SentinelResource(value = "exceptionBlockTest", fallback = "exceptionMethod",exceptionsToIgnore = MyException.class)
public String exceptionBlockTest(String str){
throw new MyException();
return "方法正常执行";
}
//异常降级方法,返回值类型,形参列表要与实际方法一致
public String exceptionMethod(String str){
System.out.println("发送异常执行的降级方法,接收参数:"+str);
return "发送异常执行的降级方法,接收参数:"+str;
}
三. @SentinelResource 降级方法与业务接口的解耦
- 根据降级的不同分为两种,针对流量控制,熔断控制等触发的降级与方法抛出异常时的异常降级
- 专门创建一个用来存放降级方法的类,类中创建对应业务接口的降级方法,降级方法必须为 static 类型,
blockHandler 触发类型的降级方法形参中必须包含 BlockException
fallback 抛出异常的降级类型,降级方法方法形参方法返回值要与对应的实际方法一致
3. blockHandler 触发降级类型
- 创建专门存放降级方法的类,该类中的降级方法必须为 static 类型,形参中必须包含 BlockException
import com.alibaba.csp.sentinel.slots.block.BlockException;
public class CustomerBlockHandler {
public static String bolckMethod1(BlockException exception){
System.out.println("降级方法执行1");
return "降级方法执行1";
}
public static String bolckMethod2(BlockException exception){
System.out.println("降级方法执行2");
return "降级方法执行2";
}
}
- 需要设置降级实际请求接口,通过注解的 blockHandlerClass 属性指定降级方法所在的类,通过注解的 blockHandler 属性指定执行哪个降级方法
//当请求该接口触发降级时,会执行 blockHandlerClass 属性指定的 CustomerBlockHandler 类中的 bolckMethod1() 方法
@GetMapping("/blockTest")
@SentinelResource(value = "blockTest",blockHandlerClass = CustomerBlockHandler.class,blockHandler = "bolckMethod1")
public String resourceTest(){
System.out.println("方法正常执行");
return "方法正常执行";
}
4. fallback 异常方式的降级
- 创建专门存放降级方法的类,该类中的降级方法必须是 static类型,并且要与实际方法的形参,返回值列表一致
public class ExceptionBlockHandler {
public static String exceptionFallBack1(String str){
System.out.println("发送异常执行的降级方法1,接收参数:"+str);
return "发生异常执行的降级方法1,接收参数:"+str;
}
public static String exceptionFallBack2(String str){
System.out.println("发送异常执行的降级方法2,接收参数:"+str);
return "发生异常执行的降级方法2,接收参数:"+str;
}
}
- 需要设置抛出异常时执行降级的接口
//当请求该接口时,如果该接口抛出了异常,则执行 fallbackClass 指定的类 ExceptionBlockHandler 中的 exceptionFallBack2()方法
@GetMapping("/testExceptionBlock")
@SentinelResource(value = "testExceptionBlock", fallbackClass = ExceptionBlockHandler.class, fallback = "exceptionFallBack2")
public String testExceptionBlock(String str){
int i = 10/0;
return "方法正常执行";
}