Sentinel源码—7.参数限流和注解的实现二

大纲

1.参数限流的原理和源码

2.@SentinelResource注解的使用和实现

2.@SentinelResource注解的使用和实现

(1)@SentinelResource注解的使用

(2)@SentinelResource注解和实现

(1)@SentinelResource注解的使用

一.引入Sentinel Spring Boot Starter依赖

复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

二.为方法添加@SentinelResource注解

下面的代码为sayHello()方法添加了@SentinelResource注解,并指定了资源名称为sayHello以及熔断降级时的回调方法fallback()。这样在请求sayHello()方法后,就可以在Sentinel Dashboard上看到此资源,然后就可以针对此资源进行一系列的规则配置了。

复制代码
@Service
public class MyService {
    @SentinelResource(value = "sayHello", fallback = "fallback")
    public String sayHello(String name) {
        return "Hello, " + name;
    }

    public String fallback(String name, Throwable throwable) {
        return "Fallback: " + name + ", reason: " + throwable.getMessage();
    }
}

(2)@SentinelResource注解和实现

利用Spring AOP拦截@SentinelResource注解,最后调用SphU.entry()方法来进行处理。

复制代码
//Aspect for methods with {@link SentinelResource} annotation.
@Aspect
public class SentinelResourceAspect extends AbstractSentinelAspectSupport {
    //SentinelResource注解
    @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();
        int resourceType = annotation.resourceType();
        //创建一个Entry对象,通过SphU.entry(resourceName)将当前方法纳入Sentinel的保护体系
        //如果当前资源的调用未触发任何Sentinel规则,则正常执行被拦截的方法,否则将执行对应的限流、熔断降级等处理逻辑
        Entry entry = null;
        try {
            entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());
            return pjp.proceed();
        } catch (BlockException ex) {
            //发生异常时,通过反射执行在注解中设置的降级方法
            return handleBlockException(pjp, annotation, ex);
        } catch (Throwable ex) {
            Class<? extends Throwable>[] exceptionsToIgnore = annotation.exceptionsToIgnore();
            //The ignore list will be checked first.
            if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) {
                throw ex;
            }
            if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) {
                traceException(ex);
                return handleFallback(pjp, annotation, ex);
            }
            //No fallback function can handle the exception, so throw it out.
            throw ex;
        } finally {
            if (entry != null) {
                entry.exit(1, pjp.getArgs());
            }
        }  
    }
}

//Some common functions for Sentinel annotation aspect.
public abstract class AbstractSentinelAspectSupport {
    ...
    protected Object handleBlockException(ProceedingJoinPoint pjp, SentinelResource annotation, BlockException ex) throws Throwable {
        //Execute block handler if configured.
        Method blockHandlerMethod = extractBlockHandlerMethod(pjp, annotation.blockHandler(), annotation.blockHandlerClass());
        if (blockHandlerMethod != null) {
            Object[] originArgs = pjp.getArgs();
            //Construct args.
            Object[] args = Arrays.copyOf(originArgs, originArgs.length + 1);
            args[args.length - 1] = ex;
            return invoke(pjp, blockHandlerMethod, args);
        }
        //If no block handler is present, then go to fallback.
        return handleFallback(pjp, annotation, ex);
    }

    private Object invoke(ProceedingJoinPoint pjp, Method method, Object[] args) throws Throwable {
        try {
            if (!method.isAccessible()) {
                makeAccessible(method);
            }
            if (isStatic(method)) {
                return method.invoke(null, args);
            }
            return method.invoke(pjp.getTarget(), args);
        } catch (InvocationTargetException e) {
            //throw the actual exception
            throw e.getTargetException();
        }
    }
    ...
}
相关推荐
超级码.里奥.农9 分钟前
零基础 “入坑” Java--- 七、数组(二)
java·开发语言
hqxstudying17 分钟前
Java创建型模式---单例模式
java·数据结构·设计模式·代码规范
挺菜的26 分钟前
【算法刷题记录(简单题)002】字符串字符匹配(java代码实现)
java·开发语言·算法
A__tao26 分钟前
一键将 SQL 转为 Java 实体类,全面支持 MySQL / PostgreSQL / Oracle!
java·sql·mysql
一只叫煤球的猫37 分钟前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
猴哥源码40 分钟前
基于Java+SpringBoot的农事管理系统
java·spring boot
面朝大海,春不暖,花不开1 小时前
Java网络编程:TCP/UDP套接字通信详解
java·网络·tcp/ip
慕y2741 小时前
Java学习第十五部分——MyBatis
java·学习·mybatis
A__tao1 小时前
SQL 转 Java 实体类工具
java·数据库·sql
喝可乐的布偶猫2 小时前
Java类变量(静态变量)
java·开发语言·jvm