Sentinel 提供了 @SentinelResource
注解用于定义资源,并提供了 AspectJ (切面)的扩展用于自动定义资源、处理 BlockException
等。
注意:注解方式埋点不支持 private 方法。
@SentinelResource
用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource
注解包含以下属性:
value
:资源名称,必需项(不能为空)
entryType
:entry 类型,可选项(默认为 EntryType.OUT
)
资源调用的流量类型,是入口流量(EntryType.IN
)还是出口流量(EntryType.OUT
),注意系统规则只对 IN 生效
/**
* @return the entry type (inbound or outbound), outbound by default
*/
EntryType entryType() default EntryType.OUT;
为了验证,添加如下两个接口,并配置系统入口流量限流规则:
@GetMapping("/out")
@SentinelResource(value = "entryTypeOut", entryType = EntryType.OUT)
public String entryTypeOut() {
return "sentinelResource-out";
}
@GetMapping("/in")
@SentinelResource(value = "entryTypeIn", entryType = EntryType.IN)
public String entryTypeIn() {
return "sentinelResource-in";
}
新增系统规则:
此时查看实时监控面板,可以看出/in的通过的QPS为1,/out的入口通过的QPS为2,所以系统规则对/in是生效的
blockHandler
/ blockHandlerClass
: blockHandler
对应处理 BlockException
的函数名称,可选项。blockHandler 函数访问范围需要是 public
,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException
。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass
为对应的类的 Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback
:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
返回值类型必须与原函数返回值类型一致;
方法参数列表需要和原函数一致,或者可以额外多一个 Throwable
类型的参数用于接收对应的异常。
@GetMapping("/fallback/{id}")
//添加SentinelResource注解的fallback属性,同时设置方法来解决Java异常
@SentinelResource(value = "fallback", fallback = "fallbackHandler")
public String fallback(@PathVariable Long id){
return "success";
}
//保证方法签名与原方法一致或加一个 Throwable 类型的参数
public String fallbackHandler(Long id, Throwable e) {
xxxxx
}
// 或者
public String fallbackHandler(Long id) {
xxxxx
}
fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass
为对应的类的 Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback
(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所以类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
返回值类型必须与原函数返回值类型一致;
方法参数列表需要为空,或者可以额外多一个 Throwable
类型的参数用于接收对应的异常。
public String defaultFallbackHandle(Throwable ex){
xxxxx
}
// 或者
public String defaultFallbackHandle(){
xxxxx
}
defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass
为对应的类的 Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore
(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
注:1.6.0 之前的版本 fallback 函数只针对降级异常(
DegradeException
)进行处理,不能针对业务异常进行处理。
特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException
时只会进入 blockHandler
处理逻辑。若未配置 blockHandler
、fallback
和 defaultFallback
,则被限流降级时会将 BlockException
直接抛出。
其实我们在使用@SentinelResource注解这两种方案的时候,会出现一些问题:
解决:@SentinelResource除了blockHandler可以设置自定义限流处理逻辑方法以外,还提供另外一个属性来设置限流处理逻辑类型blockHandlerClass属性,此属性中设置的方法必需为 static 函数,否则无法解析。
第一步
创建CustomerBlockHandler类型用于处理自定义限流处理逻辑,首先创建myhandler.CustomerBlockHandler
/**
* 此类型用来处理限流自定义逻辑
*/
public class CustomerBlockHandler {
public static String handlerException1(BlockException exception){
return "handlerException1:系统异常,请稍后重试!";
}
public static String handlerException2(BlockException exception){
return "handlerException2:网络崩溃了,请稍后重试!";
}
}
第二步
我们在SentinelResourceTestController类型中添加一个接口方法,同时设置@SentinelResource注解和blockHandlerClass属性对应的类型和这个类型中对应的处理方法
/**
* 此方法用到了自定义限流处理类型CustomerBlockHandler
* 中的handlerException1方法来处理限流逻辑。
*/
@GetMapping("/byCustomer")
@SentinelResource(value = "byCustomer",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException1")
public String byCustomer(){
return "-----byCustomer";
}
第三步
测试:给byCustomer资源添加限流规则,然后来测试在超过限流阈值时处理方法是否为CustomerBlockHandler中handlerException1来进行处理。
流控效果:
(定义如上)
注意: fallback属性和blockHandler属性的本质不同在于他们作用的异常不同
@GetMapping("/fallback/{id}")
//添加SentinelResource注解的fallback属性,同时设置方法来解决Java异常
@SentinelResource(value = "fallback", fallback = "fallbackHandler")
public String fallback(@PathVariable Long id){
if (id < 0 || id > 3) {
throw new NullPointerException("无对应的记录");
}
return "success";
}
//保证方法签名与原方法一致或加一个 Throwable 类型的参数
public String fallbackHandler(Long id, Throwable e) {
return "出现未知的记录";
}
效果(未加流控规则前):
然后,我们添加流控规则:
总结:
fallback定义的函数方法,抛出了任何异常,都会触发指定函数的执行。(除了exceptionsToIgnore 里面排除掉的异常类型)
在触发定义的流控规则后,Sentinel会自动抛出BlockException异常。只有fallback存在,没有定义blockHandler时,此时也会触发fallback定义的函数方法。
@GetMapping("/fallback/{id}")
//同时添加SentinelResource注解的fallback和blockHandler属性 exceptionsToIgnore被标注的异常将会被 原样抛出
@SentinelResource(value = "falllback", fallback = "fallbackHandler", blockHandler = "blockHandler", exceptionsToIgnore = {ArrayIndexOutOfBoundsException.class})
public String fallback(@PathVariable Long id){
if (id < 0 || id > 3) {
throw new NullPointerException("无对应的记录");
}
return "success";
}
//保证方法签名与原方法一致或加一个 Throwable 类型的参数
public String fallbackHandler(Long id, Throwable e) {
return "出现未知的记录";
}
//处理Sentinel限流
public String blockHandler(Long id, BlockException e){
return "BlockException限流";
}
添加流控规则:
exceptionsToIgnore
(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
修改代码:
@GetMapping("/fallback/{id}")
//同时添加SentinelResource注解的fallback和blockHandler属性 exceptionsToIgnore被标注的异常将会被 原样抛出
@SentinelResource(value = "falllback", fallback = "fallbackHandler", blockHandler = "blockHandler", exceptionsToIgnore = {NullPointerException.class})
public String fallback(@PathVariable Long id){
if (id < 0 || id > 3) {
throw new NullPointerException("无对应的记录");
}
return "success";
}