前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Sentinel: 使用注解限流

Sentinel: 使用注解限流

作者头像
猿天地
发布2019-05-07 18:31:48
1.1K0
发布2019-05-07 18:31:48
举报
文章被收录于专栏:猿天地猿天地

在前面我们对Sentinel做了一个详细的介绍,可以手动的通过Sentinel提供的SphU类来保护资源。

文章查看:Sentinel: 分布式系统的流量防卫兵

这种做法不好的地方在于每个需要限制的地方都得写代码,从 0.1.1 版本开始,Sentinel 提供了 @SentinelResource 注解的方式,非常方便。

要使用注解来保护资源需要引入下面的Maven依赖:

代码语言:javascript
复制
<dependency>    <groupId>com.alibaba.csp</groupId>    <artifactId>sentinel-annotation-aspectj</artifactId>    <version>1.4.1</version></dependency>

引入之后我们需要配置SentinelResourceAspect切面让其生效,因为是通过SentinelResourceAspect切面来实现的,我这边以Spring Boot中使用进行配置示列:

代码语言:javascript
复制
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
@Configurationpublic class AopConfiguration {
    @Bean    public SentinelResourceAspect sentinelResourceAspect() {        return new SentinelResourceAspect();    }
}

然后在需要限制的方法上加SentinelResource注解即可:

代码语言:javascript
复制
@SentinelResource(value = "get", blockHandler = "exceptionHandler")@Overridepublic String get(String id) {    return "http://cxytiandi.com";}
public String exceptionHandler(String id, BlockException e) {    e.printStackTrace();    return "错误发生在" + id;}
SentinelResource:value

表示资源名,必填项

SentinelResource:blockHandler

处理 BlockException 的方法名,可选项。若未配置,则将 BlockException 直接抛出。

  • blockHandler 函数访问范围需要是 public
  • 返回类型需要与原方法相匹配
  • 参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException
  • blockHandler 函数默认需要和原方法在同一个类中

如果你不想让异常处理方法跟业务方法在同一个类中,可以使用 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

业务方法:

代码语言:javascript
复制
@SentinelResource(value = "get2", blockHandler = "handleException", blockHandlerClass = { ExceptionUtil.class })@Overridepublic String get2() {    return "http://cxytiandi.com";}

异常处理类:

代码语言:javascript
复制
import com.alibaba.csp.sentinel.slots.block.BlockException;
public final class ExceptionUtil {
    public static String handleException(BlockException ex) {        System.err.println("错误发生: " + ex.getClass().getCanonicalName());        return "error";    }
}

如何测试?

我们可以在Spring Boot的启动类中定义规则,然后快速访问接口,就可以看出效果啦,或者用压力测试工具ab等。

代码语言:javascript
复制
@SpringBootApplicationpublic class App {    public static void main(String[] args) {        initFlowRules();        SpringApplication.run(App.class, args);    }
    private static void initFlowRules() {        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();        rule.setResource("get");        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);        rule.setCount(1);        rules.add(rule);
        rule = new FlowRule();        rule.setResource("get2");        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);        rule.setCount(1);        rules.add(rule);
        FlowRuleManager.loadRules(rules);    }}

源码分析

只需要配置了SentinelResourceAspect就可以使用注解,我们来简单的看下SentinelResourceAspect的源码

代码语言:javascript
复制
@Aspectpublic class SentinelResourceAspect extends AbstractSentinelAspectSupport {
    @Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)")    public void sentinelResourceAnnotationPointcut() {    }
    @Around("sentinelResourceAnnotationPointcut()")    public Object invokeResourceWithSentinel(ProceedingJoinPoint pjp) throws Throwable {        // 获取当前访问的方法        Method originMethod = resolveMethod(pjp);        // 获取方法上的SentinelResource注解        SentinelResource annotation = originMethod.getAnnotation(SentinelResource.class);        if (annotation == null) {            // Should not go through here.            throw new IllegalStateException("Wrong state for SentinelResource annotation");        }        // 获取资源名        String resourceName = getResourceName(annotation.value(), originMethod);        EntryType entryType = annotation.entryType();        Entry entry = null;        try {            entry = SphU.entry(resourceName, entryType, 1, pjp.getArgs());            Object result = pjp.proceed();            return result;        } catch (BlockException ex) {            // 处理被限制的异常,回调事先配置的异常处理方法            return handleBlockException(pjp, annotation, ex);        } catch (Throwable ex) {            Tracer.trace(ex);            throw ex;        } finally {            if (entry != null) {                entry.exit();            }        }    }}

上面是整个切面的代码,对所有加了SentinelResource注解的方法进去切入。细节代码在AbstractSentinelAspectSupport中,大家自己去看看。

欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 猿天地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SentinelResource:value
  • SentinelResource:blockHandler
  • 如何测试?
  • 源码分析
    • 欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档