To learn more about Sentinel Resources Ect, in this article I implement an AOP example using Aspectj.

Sentinel provides the @SentinelResource annotation for defining resources, and supports AspectJ extensions for automatically defining resources, handling blockexceptions, and more.

SentinelResourceAspect is the SentinelResourceAspect, which is the core aspect of Sentinel. Sentinel’s support for stream limiting, interception, and so on depends on SentinelResourceAspect. This article reviews AOP, implements an AspectJ example, and then takes you through the source code. Explore the implementation of sentinelresources ect.

1. Review Spring AOP knowledge

AOP for the abbreviation of Aspect Oriented Programming, meaning: section-oriented Programming, through pre-compilation and runtime dynamic proxy to achieve unified maintenance of program functions of a technology.

Using AOP, each part of the business logic can be isolated, thus reducing the degree of coupling between each part of the business logic, improving the reusability of the program, and improving the efficiency of development.

Common Usage Scenarios

  • Performance monitoring

Record the call time before and after method invocation, method execution is too long or timeout alarm.

  • The caching proxy

The return value of a method is cached and fetched directly from the cache the next time the method is executed.

  • Software to crack

Use AOP to modify the judgment logic of the validation class of the software.

  • log

Log the system before and after method execution.

  • Workflow system

Workflow systems need to execute business code and process engine code mixed together, so we can use AOP to separate them and hook up the business on the fly.

  • Permission to verify

Method validates whether it has permission to execute the current method before executing it. If it does not, it throws an exception that has no permission to execute the current method, which is captured by the business code.

Some concepts of AOP

  • Aspect: Declarations are similar to class declarations in Java, and contain pointcuts and Advice in aspects.

  • Joint Point: An interception point, such as a business method, that represents a point clearly defined in a program, typically including method calls, access to class members, execution of exception handler blocks, etc. It can also nest other Joint points itself.

  • Pointcut: Represents a set of joint points that are either logically combined or grouped together through wildmatches, regular expressions, etc., that indicate which methods to intercept. One Pointcut corresponds to multiple JoinPoints

  • Advice: Defines the specific actions to be done by a program point defined in the Pointcut, that is, the logic to be cut into, using before, after, and around to distinguish between code executed before, after, or instead of each joint point.

  • Target: object that is crosscut by AspectJ. A joinPoint is a line of Target, where the method starts execution, or the code that the method class calls some other method

AspectJ is one of several implementations of AOP in Spring, along with the JDK and Cglig’s dynamic proxy.

Implement AOP based on AspectJ and @Annotation interception methods

Before studying the SentinelResourceAspect source code, I started implementing an AOP instance of AspectJ, which makes the SentinelResourceAspect principle understandable by looking at the source code.

(1) Write the Annotation class

@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
@Inherited
public @interface WorkflowLogAnnotation {
    String field();
}
Copy the code

(2) Write interfaces and implementation classes

Write the interface class WorkflowService and write the implementation class WorkflowServiceImpl. Note that the WorkflowLogAnnotation is added to the method here

public class WorkflowServiceImpl implements WorkflowService {
    @Override
    @WorkflowLogAnnotation
    public void start(String bpmnXml) {
        System.out.println("Startup process"); }}Copy the code

(3) Add the cutting action

Do something before and after the process starts to add notifications, and notice that the Pointcut expression is changed to an interceptor.

@Aspect
public class WorkflowServiceAdviceAspect {

    public WorkflowServiceAdviceAspect(){

    }

    @Pointcut("annotation(Spring.WorkflowLogAnnotation)")
    public void startPoint()

    @Before("startPoint()")
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("Before execution method");
    }

    @AfterReturning("startPoint()")
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
        System.out.println("After execution of method"); }}Copy the code

(4) Add configurations

Increase in the Xml configuration, if WorkflowServiceAdviceAspect and WorkflowServiceImpl class increased @ Component, the bean declaration can use Spring’s automatic scanning to replace.

<aop:aspectj-autoproxy /> <! Define the notification content, that is, what needs to be done before and after the pointcut executes --> <bean ID ="workflowServiceAdviceAspect" class="Spring.WorkflowServiceAdviceAspect"></bean> <! -- Define proxied --> <bean id="workflowService" class="business.WorkflowServiceImpl"></bean>

Copy the code

(5) Complete the verification

Once you’ve done that, an AspectJ instance is complete, isn’t it? Take a look at the SentinelResourceAspect source code.

3, SentinelResourceAspect source code

As you can see, the SentinelResource Ect section is implemented in the same way as our example above.

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();
        Entry entry = null;
        try {
            entry = SphU.entry(resourceName, entryType, 1, 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, annotation);
                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()); }}}}Copy the code

(1) Enter the method call sphu.entry

SentinelResourceAspect uses aspect around interception, intercepting annotations annotated with SentinelResource, calling SphU. Entry (resourceName, entryType) before entering the method, Call entry.exit() when finished;

            entry = SphU.entry(resourceName, entryType, 1, pjp.getArgs());
            Object result = pjp.proceed();
Copy the code

This is the same way we use Sentinel alone.

(2) handleBlockException handles exceptions

When calling handleBlockException, it will determine whether the exception is degraded. If so, it will call fallback. Otherwise, it will call Block Handler.

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;if (isStatic(blockHandlerMethod)) {
                return blockHandlerMethod.invoke(null, args);
            }
            return blockHandlerMethod.invoke(pjp.getTarget(), args);
        }

        // If no block handler is present, then go to fallback.
        return handleFallback(pjp, annotation, ex);
Copy the code

4, summarize

Sentinel uses Aspectj to implement the section, which makes Sentinel easier to use.