Sentinel:SentinelResourceAspect

@SentinelResource 注解的使用方法

官网文档:Sentinel 注解支持

对应 Spring 中的切面:SentinelResourceAspect

/**
 * Aspect for methods with {@link SentinelResource} annotation.
 *
 * @author Eric Zhao
 */
@Aspect
public 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 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 entry = null;
        try {// 每次请求都会创建新的 entry 对象,记录了请求开始的时间,然后会在 slot chain 上经过授权,流控,降级等一系列 check 之后,没通过 check 会抛出对应的异常
            entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());// 最后会返回 StatisticsSlot 记录各项统计数据
            Object result = pjp.proceed();// 如果请求被拒绝了会抛出 BlockException,直接进入 catch 分支了,也就不会访问资源了
            return result;
        } catch (BlockException ex) {// DegradeException、FlowException 等异常的父类
            return handleBlockException(pjp, annotation, ex);// 处理请求被拒绝的情况 blockHandler,如果没有 blockHandler 则会尝试调用 fallback 方法
        } 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;// 该异常属于 ignore,那么直接上抛,不做处理
            }
            if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) {
                traceException(ex);// 属于需要 trace 的异常,将该异常放入 entry 中,exit 时去处理
                return handleFallback(pjp, annotation, ex);// 调用可能存在的 fallback 方法
            }

            // No fallback function can handle the exception, so throw it out.
            throw ex;
        } finally {
            if (entry != null) {
                entry.exit(1, pjp.getArgs());// entry 和 exit 成对使用,记录最终请求的响应时间
            }
        }
    }
}

从切面中可以看到 Sentinel 的使用大致分 3 步:

  1. SphU.entry(...)
    请求进来前先调用 entry(...)方法,它有一个 String resourceName 参数用来表示要访问的资源。内部先创建一个全新的 Entry 对象,然后进行链式的规则校验:授权、流控、降级、系统保护、黑名单等。
    若通过了规则校验,则放行本次请求并记录统计信息;否则抛出 BlockException 的子类对象,对应规则链上第一个未通过的规则,开发者通过 catch 这个异常并判断其类别来处理请求被拒绝的业务逻辑。

  2. 访问资源
    通过规则校验的请求则可以访问资源,资源先简单粗暴的理解成将要调用的方法。
    若在访问资源的过程中出现了错误,开发者可以 catch Throwable 并用 Tracer.trace(ex) 将异常放入对应的 Entry 对象。

  3. entry.exit(...)
    entry(...)方法和 entry.exit(...)必须成对使用,通常 entry.exit(...) 放在 finally 中,确保它最后会被执行。
    该方法对本次请求进行统计收尾工作,比如:计算本次请求的响应时长,处理第 2 步中可能存在的异常等。

Sentinel 主工作流程:

  1. 工作原理

  2. 流程图:来源 https://blog.csdn.net/prestigeding/article/details/103842382
    Sentinel:SentinelResourceAspect

  3. slot chain 架构图:

    Sentinel:SentinelResourceAspect

Sentinel:SentinelResourceAspect

上一篇:HTML中添加meta元数据内容


下一篇:Ajax(1) —— Ajax基础