在 SpringCloudAlibaba-Sentinel 这篇文档中,我们已经介绍了大致的Sentinel相关知识。
但是 @SentinelResource 这个注解在那篇文档中并没有过多提及其详细内容,也就是简单提了一嘴。
那篇文档的 注解介绍位置 :https://www.yuque.com/shmily-kbnvv/xxbj/ci2gs5#9lIy9 //todo 待修改成csdn地址
我们在此进行一个详细介绍,首先此注解类似于Hystrix中的 @HystrixCommand
注解,指示Sentinel资源的定义,是定义在方法上的注解,定义控制资源以及如何配置控制策略。
比如控制某个方法被限流了、被熔断了、报错了之后应该调用哪个方法。
通过查看源码,我们可以看到该注解一共有这么多个属性:
然后我们对它一一进行解释。
然后我们对其进行一一的详细介绍:
/**
* @return name of the Sentinel resource
*/
String value() default "";
我们可以通过 @SentinelResource
注解的value值定义该方法对应的资源名。
举个例子:
//这两种写法是一样的,但是当配置多个参数的时候,就必须带上value这个属性名了。
@SentinelResource("helloSentinelResource")
// @SentinelResource(value = "helloSentinelResource")
public String helloSentinelResource(){
return "helloSentinelResource";
}
那么使用这个注解并配置此属性有什么作用呢?
这个注解的value值指定了我们配置的此api资源的名称,在我们的限流、熔断的配置中,均可以使用(限流、熔断中也可以使用@RequestMapping配置的url)。
我们下面举个限流的例子:
定义了一个接口:
@RequestMapping("/helloRequestMapping")
@SentinelResource("helloSentinelResource")
public String sentinelResource(){
return "sentinelResource";
}
在Sentinel控制台进行配置:
首先使用 @RequestMapping
的值进行配置并保存。
连续访问此接口两次(一秒内),会发现:接口被限流了。
然后再使用 @SentinelResource
的值进行配置并保存(记得删除刚刚配置的内容)。
连续访问此接口两次(一秒内),会发现:接口被限流了(虽然展示内容不一样,但是都被限流了是实打实的)。
资源调用的流量类型,入口流量还是出口流量。
/**
* @return the entry type (inbound or outbound), outbound by default
*/
EntryType entryType() default EntryType.OUT;
为了验证,添加如下两个接口,并配置系统入口流量限流规则:
@RequestMapping("/out")
@SentinelResource(value = "entryTypeOut",entryType = EntryType.OUT)
public String entryTypeOut() throws InterruptedException {
return "sentinelResource";
}
@RequestMapping("/in")
@SentinelResource(value = "entryTypeIn",entryType = EntryType.IN)
public String entryTypeIn() throws InterruptedException {
return "sentinelResource";
}
然后对每个接口都进行1秒钟2次的访问,我们可以发现,entryType = EntryType.OUT
的接口没有被限流,entryType = EntryType.IN
的接口被限流了。
资源的分类(类型)
用于标识资源的分类,0-通用、1-WEB、2-RPC、3-GATEWAY、4-SQL,在 ResourceTypeConstants 类里有定义。
这个数字对应啥我是通过官方文档、源码、注解等都都没找到,问别人才知道的。如果谁看到了在哪有相关信息能指引到这个类,告诉我一声。
/**
* @return the classification (type) of the resource
* @since 1.7.0
*/
int resourceType() default 0;
在Sentinel的实时监控中有个字段是资源分类,可以将资源分类作为条件。
参考:https://github.com/alibaba/Sentinel/wiki/实时监控#资源的秒级日志
块异常函数的名称,默认为空。
blockHandler 对应处理 BlockException 的方法名称,可选项。
正常来说我们如果达到了限流阈值、被熔断了报错之后,是会将500错误页面进行返回的。如果我们配置了blockHandler这个属性,他就会执行名称为这个属性的值的方法。
/**
* @return name of the block exception function, empty by default
*/
String blockHandler() default "";
配置作为这个属性值的方法有几个要求:
测试:
编写两个方法,一个我们访问的方法,一个访问出错了(被限流、熔断)之后访问的方法,并在控制台进行限流配置。
@RequestMapping("/blockHandler")
@SentinelResource(value = "blockHandler", blockHandler = "blockHandlerErr")
public String blockHandler() {
return "blockHandler O(∩_∩)O";
}
public String blockHandlerErr(BlockException be) {
return "blockHandler ┭┮﹏┭┮";
}
由于配置的限流阈值是1,所以当一秒钟访问一次的时候显示 blockHandler
方法的返回内容,访问两次以上的时候显示 blockHandlerErr
方法的返回内容。
指定块处理方法所在的类
fallback 方法默认需要和原方法在同一个类中,如果指定了blockHandlerClass属性的值,则使用指定类中的方法。
如果是其他类中的方法,该方法必须是静态(static)的。
/**
* The {@code blockHandler} is located in the same class with the original method by default.
* However, if some methods share the same signature and intend to set the same block handler,
* then users can set the class where the block handler exists. Note that the block handler method
* must be static.
*
* @return the class where the block handler exists, should not provide more than one classes
*/
Class<?>[] blockHandlerClass() default {};
测试:
使用 blockHandlerClass
参数指定需要使用哪个类中的方法,注意指定类中的方法一定要是静态的,无论是其他的类还是本类(当然,本类中的方法不需要用这个参数,直接就默认本类,而且不需要静态,如果指定了本类的话还需要将指定方法改成静态的,多此一举,没事找事呢这是)。
然后进行限流控制,设置阈值为1,当1秒钟访问一次的时候正常,访问两次的时候就会调用指定类中的方法。
后备函数的名称,默认为空,可选项。
用于在抛出异常的时候提供 fallback 处理逻辑。 fallback 方法可以针对所有类型的异常(除了 exceptionsToIgnore 参数里面排除掉的异常类型)进行处理。
和blockHandler使用方法一样,只不过是处理的异常不一样。
如果配置了blockHandler,限流、熔断的时候会执行blockHandler指定的方法,其他的异常执行 fallback 指定的方法。如果没配置,也执行fallback中配置的方法。
/**
* @return name of the fallback function, empty by default
*/
String fallback() default "";
测试:
如果配置了blockHandler,限流、熔断的时候会执行blockHandler指定的方法,其他的异常执行 fallback 指定的方法。
public String blockHandlerErr(BlockException be) {
return "blockHandler ┭┮﹏┭┮";
}
@RequestMapping("/fallback")
@SentinelResource(value = "fallback", fallback = "fallbackErr", blockHandler = "blockHandlerErr")
public String fallback() {
int i = 1 / 0;
return "fallback O(∩_∩)O";
}
public String fallbackErr() {
return "fallback ┭┮﹏┭┮";
}
如果没配置blockHandler,限流、熔断的时候也执行fallback中配置的方法。
public String blockHandlerErr(BlockException be) {
return "blockHandler ┭┮﹏┭┮";
}
@RequestMapping("/fallback")
@SentinelResource(value = "fallback", fallback = "fallbackErr")
public String fallback() {
int i = 1 / 0;
return "fallback O(∩_∩)O";
}
public String fallbackErr() {
return "fallback ┭┮﹏┭┮";
}
如果没有配置fallback的值,默认都会走到这里来。 默认的 fallback 方法名称,可选项,通常用于通用的 fallback 逻辑。 默认 fallback 方法可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。 若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。
测试:
@RequestMapping("/fallback")
@SentinelResource(value = "fallback", fallback = "fallbackErr",defaultFallback = "defaultFallbackErr")
public String fallback() {
int i = 1 / 0;
return "fallback O(∩_∩)O";
}
public String fallbackErr() {
return "fallback ┭┮﹏┭┮";
}
public String defaultFallbackErr() {
return "defaultFallback ┭┮﹏┭┮";
}
@RequestMapping("/fallback")
@SentinelResource(value = "fallback", defaultFallback = "defaultFallbackErr")
public String fallback() {
int i = 1 / 0;
return "fallback O(∩_∩)O";
}
public String fallbackErr() {
return "fallback ┭┮﹏┭┮";
}
public String defaultFallbackErr() {
return "defaultFallback ┭┮﹏┭┮";
}
指定块处理方法所在的类
fallback 方法默认需要和原方法在同一个类中,如果指定了blockHandlerClass属性的值,则使用指定类中的方法。
如果是其他类中的方法,该方法必须是静态(static)的。
/**
* The {@code fallback} is located in the same class with the original method by default.
* However, if some methods share the same signature and intend to set the same fallback,
* then users can set the class where the fallback function exists. Note that the shared fallback method
* must be static.
*
* @return the class where the fallback method is located (only single class)
* @since 1.6.0
*/
Class<?>[] fallbackClass() default {};
实际使用和 blockHandlerClass
几乎一样,这里就不展示测试过程了。
用于指定哪些异常被统计,与 exceptionsToIgnore 相反。可选。默认Throwable。
一般与 fallback 搭配使用。
/**
* @return the list of exception classes to trace, {@link Throwable} by default
* @since 1.5.1
*/
Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};
测试:
编写两个方法,一个接口方法、一个fallback指定方法。
接口方法中,当传入参数 num=1
的时候,抛出 ArrayIndexOutOfBoundsException
异常,当传入参数 num=2
时,抛出 NumberFormatException
异常。
通过 exceptionsToTrace 和 fallback控制,只统计 ArrayIndexOutOfBoundsException
异常,当出现 ArrayIndexOutOfBoundsException
异常的时候,调用 exceptionsToTraceFallbackErr 方法(其他异常则不进行处理)。
@RequestMapping("/exceptionsToTrace")
@SentinelResource(value = "exceptionsToTrace",
exceptionsToTrace = ArrayIndexOutOfBoundsException.class,
fallback = "exceptionsToTraceFallbackErr")
public String exceptionsToTrace(int num) {
if (num == 1) {
int[] ints = {1, 2, 3};
System.out.println(ints[10]);
} else {
int i = Integer.valueOf("s");
}
return "exceptionsToTrace O(∩_∩)O";
}
public String exceptionsToTraceFallbackErr(int num) {
return "exceptionsToTraceFallbackErr ┭┮﹏┭┮";
}
用于指定哪些异常被忽略,与 exceptionsToTrace 相反。可选。默认空。
一般与 fallback 搭配使用。
/**
* Indicates the exceptions to be ignored. Note that {@code exceptionsToTrace} should
* not appear with {@code exceptionsToIgnore} at the same time, or {@code exceptionsToIgnore}
* will be of higher precedence.
*
* @return the list of exception classes to ignore, empty by default
* @since 1.6.0
*/
Class<? extends Throwable>[] exceptionsToIgnore() default {};
测试:
编写两个方法,一个接口方法、一个fallback指定方法。
接口方法中,当传入参数 num=1
的时候,抛出 ArrayIndexOutOfBoundsException
异常,当传入参数 num=2
时,抛出 NumberFormatException
异常。
通过 exceptionsToIgnore 和 fallback控制,不统计 ArrayIndexOutOfBoundsException
异常,当出现 ArrayIndexOutOfBoundsException
异常的时候,调用 exceptionsToIgnoreFallbackErr 方法(其他异常则不进行处理)。
@RequestMapping("/exceptionsToIgnore")
@SentinelResource(value = "exceptionsToIgnore",
exceptionsToTrace = ArrayIndexOutOfBoundsException.class,
fallback = "exceptionsToIgnoreFallbackErr")
public String exceptionsToIgnore(int num) {
if (num == 1) {
int[] ints = {1, 2, 3};
System.out.println(ints[10]);
} else {
int i = Integer.valueOf("s");
}
return "exceptionsToIgnore O(∩_∩)O";
}
public String exceptionsToIgnoreFallbackErr(int num) {
return "exceptionsToIgnoreFallbackErr ┭┮﹏┭┮";
}
额外提一个类 SentinelResourceAspect ,也就是这个注解怎么实现的。
如果想看@SentinelResource是怎么生效的,就看下这个类的源码就懂啦。
完整路径:com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect.java
相关代码下载地址:https://download.csdn.net/download/wangguohui0726/16698689