ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

微服务系列:Sentinel 之 @SentinelResource 注解配置

2022-02-05 10:30:00  阅读:168  来源: 互联网

标签:testResource String SentinelResource id public Sentinel 注解 fallback testFallback


在上面的学习 Sentinel 的各种规则的文章中,我们多次使用到 @SentinelResource 注解,虽然在入门篇 微服务系列:Spring Cloud Alibaba 之 Sentinel 详细入门 中提到过 @SentinelResource 注解,但我觉得还是需要更详细的学习一下这个注解,毕竟我们用来定义 Sentinel 的资源,大概率还是使用此注解来定义,个人觉得,大家现在应该都比较倾向于注解式开发。

话不多说,开始今天的学习。

一、@SentinelResource 注解

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:

  • value:资源名称,必需项(不能为空)

  • entryType:entry 类型,可选项(默认为 EntryType.OUT

  • blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

  • fallback/fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:

    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • defaultFallback

    (since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:

    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

在前面的学习中有这样一个案例:

@Service
public class IUserServiceImpl implements IUserService {

    public static final String RESOURCE_NAME = "selectUserByName";

    @Override
    @SentinelResource(value = RESOURCE_NAME, blockHandler = "selectUserByNameBlockHandler", fallback = "selectUserByNameFallback")
    public String selectUserByName(String username) {
        return "{\"userName\": " + username + ", \"age\": 25}";
    }

    // 服务流量控制处理,参数最后多一个 BlockException,其余与原函数一致。
    public String selectUserByNameBlockHandler(String username, BlockException ex)
    {
        System.out.println("selectUserByNameBlockHandler异常信息:" + ex.getMessage());
        return "{\"code\":\"500\",\"msg\": \"" + username + "服务流量控制处理\"}";
    }

    // 服务熔断降级处理,函数签名与原函数一致或加一个 Throwable 类型的参数
    public String selectUserByNameFallback(String username, Throwable throwable)
    {
        System.out.println("selectUserByNameFallback异常信息:" + throwable.getMessage());
        return "{\"code\":\"500\",\"msg\": \"" + username + "服务熔断降级处理\"}";
    }

}

直接看上面的文字可能不太直观,我们直接实战来操作一下

二、blockHandlerfallback

在前面的学习中,我们最常用的就是这两个属性了。

1. blockHandler

blockHandlerSentinel 的限流兜底方法

@RestController
public class ResourceController {

    @GetMapping("/testResource")
    @SentinelResource(value = "testResource")
    public String testResource(){
        return "testResource....";
    }
}

@GetMapping("/testResource")
@SentinelResource(value = “testResource”)

/testResourcetestResource 一个是按 url 限流,一个是按资源名称限流

1.1、给 /testResource 添加一个限流规则

image-20220201180249751

image-20220201180334675

此时访问地址:localhost:9201/testResource 会返回 Sentinel 默认的限流提示

image-20220201180412813

1.2、给资源名称 testResource 配置一个流控规则

/testReource 的流控规则删掉

image-20220201180643983

再访问地址:localhost:9201/testResource 会直接报错。

image-20220201180812897

我们再修改 @SentinelResource(value = "testResource") 属性添加一个限流成功的兜底方法

@GetMapping("/testResource")
@SentinelResource(value = "testResource", blockHandler = "resourceBlockHandler")
public String testResource(){
    return "testResource....";
}

public String resourceBlockHandler(BlockException ex){
    return "服务不可用!";
}

重启项目,重新添加 testResource 资源名称的流控规则,访问地址,触发限流后就进入了我们自定义的 blockHandler 方法中

image-20220201181047429

1.3、blockHandlerClass

上面 1.2 的配置形式存在的问题:

  • 自定义的处理方法和业务代码耦合在一起,不直观;
  • 每个业务方法都添加一个兜底方法,代码急剧膨胀;
  • 全局统一的处理方法没有体现。

所以就有了 fallbackClass 属性的配置

**①、**自定义一个全局的 handler CustomerBlockHandler.java

public class CustomerBlockHandler {

    public static String handlerException(@PathVariable int id, BlockException e) {
        return "用户自定义,全局 handlerException---1";
    }

    public static String handlerException2(@PathVariable int id, BlockException e) {
        return "用户自定义,全局 handlerException---2";
    }
}

注意对应的函数必需为 static 函数,否则无法解析。

**②、**使用 blockHandlerClass 属性

@RestController
public class ResourceController {

    @GetMapping("/testResource")
    @SentinelResource(value = "testResource",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public String testResource(){
        return "testResource....";
    }
}

2. fallback

fallbackJava 自身的运行时异常兜底方法

2.1、定义 testFallback 资源

@GetMapping("/testFallback/{id}")
@SentinelResource(value = "testFallback")
public String testFallback(@PathVariable int id){
    if (id == 1) {
        throw new IllegalArgumentException("IllegalArgumentException,非法参数异常!");
    } else if (id == 2) {
        throw new NullPointerException("NullPointerException, 空指针异常!");
    }
    return "testFallback....";
}

接口中模拟抛出 Java 运行时异常,此时访问该接口,会直接出现 Error Page

image-20220201212118672

image-20220201212145786

2.2、添加 fallback 属性

@GetMapping("/testFallback/{id}")
@SentinelResource(value = "testFallback", fallback = "handlerFallback")
public String testFallback(@PathVariable int id){
    if (id == 1) {
        throw new IllegalArgumentException("IllegalArgumentException,非法参数异常!");
    } else if (id == 2) {
        throw new NullPointerException("NullPointerException, 空指针异常!");
    }
    return "testFallback....";
}

public String handlerFallback(@PathVariable int id, Throwable e) {
    return "服务器内部错误:" + e.getMessage();
}

重启项目,访问地址:localhost:9201/testFallback/1

image-20220201212447809

2.3、fallbackClass 属性

同样的 fallback 同样有类似 blockHandlerClass 的属性 fallbackClass

public class CustomerFallback {

    public static String handlerFallback(@PathVariable int id, Throwable e) {
        return "服务器内部错误:" + e.getMessage();
    }

    public static String handlerFallback2(@PathVariable int id, Throwable e) {
        return "服务器内部错误2:" + e.getMessage();
    }
}
@GetMapping("/testFallback/{id}")
@SentinelResource(value = "testFallback", fallbackClass = CustomerFallback.class, fallback = "handlerFallback2")
public String testFallback(@PathVariable int id){
    if (id == 1) {
        throw new IllegalArgumentException("IllegalArgumentException,非法参数异常!");
    } else if (id == 2) {
        throw new NullPointerException("NullPointerException, 空指针异常!");
    }
    return "testFallback....";
}

浏览器访问:localhost:9201/testFallback/1

image-20220201213505235

注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理

3. blockHandler VS fallback

特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandlerfallbackdefaultFallback,则被限流降级时会将 BlockException 直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)。

两者都配置

@GetMapping("/testFallback/{id}")
//@SentinelResource(value = "testFallback")
@SentinelResource(value = "testFallback",
        blockHandlerClass = CustomerBlockHandler.class,
        blockHandler = "handlerException2",
        fallbackClass = CustomerFallback.class,
        fallback = "handlerFallback2")
public String testFallback(@PathVariable int id){
    if (id == 1) {
        throw new IllegalArgumentException("IllegalArgumentException,非法参数异常!");
    } else if (id == 2) {
        throw new NullPointerException("NullPointerException, 空指针异常!");
    }
    return "testFallback....";
}

对资源 testFallback 新增流控规则

image-20220201215331045

访问地址:localhost:9201/testFallback/1,这时还没有触发限流

image-20220201215447346

快速刷新该地址,进入到 blockHandler

image-20220201215554369

被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑

三、exceptionsToIgnore

exceptionsToIgnore 这个就比较简单了

用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

我们来试一下

@GetMapping("/testFallback/{id}")
@SentinelResource(value = "testFallback",
        exceptionsToIgnore = IllegalArgumentException.class,
        fallbackClass = CustomerFallback.class,
        fallback = "handlerFallback2")
public String testFallback(@PathVariable int id){
    if (id == 1) {
        throw new IllegalArgumentException("IllegalArgumentException,非法参数异常!");
    } else if (id == 2) {
        throw new NullPointerException("NullPointerException, 空指针异常!");
    }
    return "testFallback....";
}

浏览器访问:localhost:9201/testFallback/1

image-20220201220148128

IllegalArgumentException 确实被排除掉了,没有进入 fallback 逻辑中。

至此,本文结束。

PS: 都看到这里了,点个赞吧,彦祖

标签:testResource,String,SentinelResource,id,public,Sentinel,注解,fallback,testFallback
来源: https://blog.csdn.net/zhang33565417/article/details/122788422

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有