当前位置:网站首页>Sentinel源码(一)SentinelResourceAspect
Sentinel源码(一)SentinelResourceAspect
2022-08-02 14:01:00 【Ethan_199402】
本文版本:1.8.0
SentinelResourceAspect
Sentinel是做什么的就不详细介绍了,有需要的请点击注解支持
接下来就从SentinelResourceAspect开始探索Sentinel
我们知道,只要在方法上加上SentinelResource,就可以配置一些限流熔断策略,那么就要看这个注解被用在源码的什么地方
@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 = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());
Object result = pjp.proceed();
return result;
} 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());
}
}
}
}
可以看到,SentinelResourceAspect继承于AbstractSentinelAspectSupport,定义如下切面
@Pointcut("@annotation(com.alibaba.csp.sentinel.annotation.SentinelResource)")
public void sentinelResourceAnnotationPointcut() {
}
也就是所有使用到@SentinelResource的地方,可以看到环绕通知中使用entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());
进行代码增强,紧接着就执行真正的代码逻辑Object result = pjp.proceed();
,所以可以知道所有的奥秘都在SphU.entry()这个方法中,关于他的详细介绍我们放在下一篇文中章中
异常
接下来看发生异常时,这个aop做了什么
阻塞异常
由于触发流控制、断路或系统保护而被 Sentinel 阻塞
catch (BlockException ex) {
return handleBlockException(pjp, annotation, ex);
那么就看handleBlockException方法
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;
try {
if (isStatic(blockHandlerMethod)) {
return blockHandlerMethod.invoke(null, args);
}
return blockHandlerMethod.invoke(pjp.getTarget(), args);
} catch (InvocationTargetException e) {
// throw the actual exception
throw e.getTargetException();
}
}
// If no block handler is present, then go to fallback.
return handleFallback(pjp, annotation, ex);
}
首先提取blockhandler方法extractBlockHandlerMethod
private Method extractBlockHandlerMethod(ProceedingJoinPoint pjp, String name, Class<?>[] locationClass) {
if (StringUtil.isBlank(name)) {
return null;
}
boolean mustStatic = locationClass != null && locationClass.length >= 1;
Class<?> clazz;
if (mustStatic) {
clazz = locationClass[0];
} else {
// By default current class.
clazz = pjp.getTarget().getClass();
}
MethodWrapper m = ResourceMetadataRegistry.lookupBlockHandler(clazz, name);
if (m == null) {
// First time, resolve the block handler.
Method method = resolveBlockHandlerInternal(pjp, name, clazz, mustStatic);
// Cache the method instance.
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, name, method);
return method;
}
if (!m.isPresent()) {
return null;
}
return m.getMethod();
}
可以看到,根据传进来的locationClass作为寻找blockhandler的基类,如果没有传,那就是当前类。
如果提供的类中没有对应的blockhandler方法,也会resolveBlockHandlerInternal方法找到
当获得了blockHandlerMethod,接下来就调用这个方法,如果没有获得blockHandlerMethod,则调用fallback
//当获得了blockHandlerMethod,接下来就调用这个方法
if (blockHandlerMethod != null) {
Object[] originArgs = pjp.getArgs();
// Construct args.
Object[] args = Arrays.copyOf(originArgs, originArgs.length + 1);
args[args.length - 1] = ex;
try {
if (isStatic(blockHandlerMethod)) {
return blockHandlerMethod.invoke(null, args);
}
return blockHandlerMethod.invoke(pjp.getTarget(), args);
} catch (InvocationTargetException e) {
// throw the actual exception
throw e.getTargetException();
}
}
//如果没有获得blockHandlerMethod,则调用fallback
// If no block handler is present, then go to fallback.
return handleFallback(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;
首先如果是SentinelResource注解上配置的需要忽略的异常,则直接抛出该异常
// The ignore list will be checked first.
if (exceptionsToIgnore.length > 0 && exceptionBelongsTo(ex, exceptionsToIgnore)) {
throw ex;
}
如果是SentinelResource注解配置的需要跟踪的异常(默认是Throwable),则调用Fallback方法
if (exceptionBelongsTo(ex, annotation.exceptionsToTrace())) {
traceException(ex);
return handleFallback(pjp, annotation, ex);
}
那么再看一下handleFallback方法
protected Object handleFallback(ProceedingJoinPoint pjp, String fallback, String defaultFallback,
Class<?>[] fallbackClass, Throwable ex) throws Throwable {
Object[] originArgs = pjp.getArgs();
// Execute fallback function if configured.
Method fallbackMethod = extractFallbackMethod(pjp, fallback, fallbackClass);
if (fallbackMethod != null) {
// Construct args.
int paramCount = fallbackMethod.getParameterTypes().length;
Object[] args;
if (paramCount == originArgs.length) {
args = originArgs;
} else {
args = Arrays.copyOf(originArgs, originArgs.length + 1);
args[args.length - 1] = ex;
}
try {
if (isStatic(fallbackMethod)) {
return fallbackMethod.invoke(null, args);
}
return fallbackMethod.invoke(pjp.getTarget(), args);
} catch (InvocationTargetException e) {
// throw the actual exception
throw e.getTargetException();
}
}
// If fallback is absent, we'll try the defaultFallback if provided.
return handleDefaultFallback(pjp, defaultFallback, fallbackClass, ex);
}
可以看到,类似于handleBlockException方法首先使用extractFallbackMethod获得fallback方法,根据传进来的locationClass作为寻找fallbackMethod的基类,如果没有传,那就是当前类。
如果提供的类中没有对应的fallback方法,也会resolveFallbackInternal方法找到
当获得了fallbackMethod,接下来就调用这个方法,如果没有获得fallbackMethod,则调用defaultFallback,同样的如果没有配置defaultFallback,则会直接抛出异常
protected Object handleDefaultFallback(ProceedingJoinPoint pjp, String defaultFallback,
Class<?>[] fallbackClass, Throwable ex) throws Throwable {
// Execute the default fallback function if configured.
Method fallbackMethod = extractDefaultFallbackMethod(pjp, defaultFallback, fallbackClass);
if (fallbackMethod != null) {
// Construct args.
Object[] args = fallbackMethod.getParameterTypes().length == 0 ? new Object[0] : new Object[] {
ex};
try {
if (isStatic(fallbackMethod)) {
return fallbackMethod.invoke(null, args);
}
return fallbackMethod.invoke(pjp.getTarget(), args);
} catch (InvocationTargetException e) {
// throw the actual exception
throw e.getTargetException();
}
}
// If no any fallback is present, then directly throw the exception.
throw ex;
}
总结
- SentinelResource注解可以配置两个Handler,一个是由于触发流控制、断路或系统保护而被 Sentinel 阻塞时,需要调用的blockHandler,一个是可配置的异常发生时(默认为Throwable)需要调用的fallback
- 当抛出BlockException时,调用handleBlockException方法寻找配置的blockHandler并调用
- 当抛出Throwable时,如果配置了exceptionsToIgnore,配置的异常列表会被直接抛出,无论是否配置在exceptionsToTrace列表中;如果该异常也没有配置在exceptionsToTrace中,也会抛出;如果配置在exceptionsToTrace中,则根据handleFallback方法找到配置的fallback并调用
- 如果blockHandler没有配置,会调用fallback,如果fallback没有配置,则调用defaultFallback,如果defaultFallback也没有配置则直接抛出异常
边栏推荐
- uview 2.x版本 tabbar在uniapp小程序里头点击两次才能选中图标
- 数据机构---第六章图---图的遍历---选择题
- 2022-08-02日报:2022年7月最热的10篇AI论文
- How to connect DBeaver TDengine?
- Embedded system driver primary [2] - based on character device driver _ basic framework
- C language improvement (3)
- WiFi Association&Omnipeek抓包分析
- 栈 && 队列
- rhce第三天作业
- RKMPP库快速上手--(一)RKMPP功能及使用详解
猜你喜欢
Differences and concepts between software testing and hardware testing
How to connect DBeaver TDengine?
binary search && tree
玉溪卷烟厂通过正确选择时序数据库 轻松应对超万亿行数据
eclipse连接数据库后插入数据报错null
方舟生存进化淘宝面板服务器是怎么一回事?
tinymce-plugins
乐心湖‘s Blog——MySQL入门到精通 —— 囊括 MySQL 入门 以及 SQL 语句优化 —— 索引原理 —— 性能分析 —— 存储引擎特点以及选择 —— 面试题
基于深度学习的图像检索方法!
How to do short video food from the media?5 steps to teach you to get started quickly
随机推荐
二叉树的类型、构建、遍历、操作
软件测试和硬件测试的区别及概念
eclipse连接数据库后插入数据报错null
LeetCode(剑指 Offer)- 53 - II. 0~n-1中缺失的数字
C language improvement (3)
Supervision strikes again, what about the market outlook?2021-05-22
SQL函数 TRUNCATE
保姆级教程:写出自己的移动应用和小程序(篇三)
Fabric.js 动态设置字号大小
【C语言】细品分支结构——switch语句
You can't accept 60% slump, there is no eligible for gain of 6000% in 2021-05-27
网络安全第三次作业
rpm包的卸载与安装[通俗易懂]
FreeBSD bnxt以太网驱动源码阅读记录三:
RKMPP库快速上手--(一)RKMPP功能及使用详解
wait() ,notify(),notifyAll()以及wait()与sleep()比较
网络安全第六次作业
打破文件锁限制,以存储力量助力企业增长新动力
泡利不相容原理适用的空间范围(系统)是多大?
配置zabbix自动发现和自动注册。