大纲
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();
}
}
...
}