Sentinel提供了@SentinelResource
注解用于定义注解,并提供了AspectJ的扩展用于自定义资源、处理BlockException
等。
注解解释:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {
// 定义的资源名
String value() default "";
// entry类型, 默认是 EntryType.OUT
EntryType entryType() default EntryType.OUT;
// 资源类型
int resourceType() default 0;
// 对应处理blockException的函数名称
String blockHandler() default "";
// 当希望使用其他类的函数时,可以通过这个来指定对应类的Class对象,注意对应的函数必须为static函数
Class<?>[] blockHandlerClass() default {};
// fallback函数名称,用于在抛出异常时提供fallback处理逻辑,可以处理所有类型的异常
String fallback() default "";
// 默认的fallback函数名称
String defaultFallback() default "";
// 当使用其他类的函数时
Class<?>[] fallbackClass() default {};
// 要跟踪的异常类列表
Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};
// 忽略这些异常
Class<? extends Throwable>[] exceptionsToIgnore() default {};
}
当出现异常执行上述注解中的指定的处理函数时,这时我们就要利用Spring的AOP特性。
先定义个切入点:
@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());
}
}
}
简单的说,就是先获取加了该注解的方法,然后解析获取注解里面的参数名等信息,然后根据获取的信息执行一个Sphu.entry()
方法包装资源,判断是否需要限流等操作,可以通过的话,再利用反射执行业务逻辑代码;如果没有通过限流等操作,就会抛出BlockException
的子类异常,然后获取在注解中定义的函数方法名,利用反射机制再进行执行。
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);
}
参考文章:
注解支持
网友评论