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();
        }
    }
    ...
}
相关推荐
古法老登瞎折腾8 小时前
大数据智能运维实战(十一):运维 MCP 的工程化——权限、限流、审计与错误处理
java·大数据·运维·spring ai·mcp
智能运维指南9 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
yz_aiks9 小时前
Spring AI 2.1 ChatMemory 已过时用什么替代:迁移到 Session Memory 实战(JDBC 存储与会话压缩)
java·spring boot·大模型·ai agent·spring ai
金銀銅鐵10 小时前
[Java] 用 GUI 展示 EnumMap 增删键值对时的内部变化
java·后端·ai编程
学长毕设10 小时前
基于SpringBoot的上门洗车服务系统设计与实现
java·spring boot·后端
jason成都10 小时前
RTKLIB-Java 多基线联合RTK:FIX率从0%到91.5%的三层根因修复
java·gnss·rtklib·rtklib_java
鱼宵10 小时前
Stream 终端操作一次讲透:collect、count、reduce 怎么选
java·stream·终端操作
白山编程大哥10 小时前
Java 后端如何优雅地把 List 集合返回给前端
java·前端·list
Linux运维技术栈11 小时前
CVE-2026-91403 高危漏洞修复:Rocky Linux 9 多版本 JDK 环境清理实操
java·linux·运维
On The Road :11 小时前
Java 多线程详解:从入门到线程安全
java·python·安全