Anyone who has worked with the Spring framework for development, and has more or less used its AOP features, knows that there are @before, @around, and @after advice. Recently, I have also used AOP functionality to fulfill two requirements for output logging and permission control in my project. I used @before and @around advice. However, in the process of use, the order of their execution is not clear. In order to figure out what order these advice is executed in different situations, I have run a test and recorded it here for later review.

Prerequisites The concepts of AOP related classes (Aspects, Pointcuts, and so on) are not explained in this article. How to get the Spring framework to scan AOP is also not explained in this article. When a method is intercepted by only one Aspect, what is the order in which the different advice in that Aspect is executed? Please look at:

Add a PointCut class that intercepts all methods in all classes under the Test package.

package test;

import org.aspectj.lang.annotation.Pointcut;

public class PointCuts {

@Pointcut(value = "within(test.*)")
public void aopDemo() {

}

}

Advice in this class will use the pointcut above. See the value attribute of each advice for how to use it.

package test;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;

@Component

@Aspect

public class Aspect1 {

@Before(value = "test.PointCuts.aopDemo()")
public void before(JoinPoint joinPoint) {
    System.out.println("[Aspect1] before advise");
}

@Around(value = "test.PointCuts.aopDemo()")
public void around(ProceedingJoinPoint pjp) throws  Throwable{
    System.out.println("[Aspect1] around advise 1");
    pjp.proceed();
    System.out.println("[Aspect1] around advise2");
}

@AfterReturning(value = "test.PointCuts.aopDemo()")
public void afterReturning(JoinPoint joinPoint) {
    System.out.println("[Aspect1] afterReturning advise");
}

@AfterThrowing(value = "test.PointCuts.aopDemo()")
public void afterThrowing(JoinPoint joinPoint) {
    System.out.println("[Aspect1] afterThrowing advise");
}

@After(value = "test.PointCuts.aopDemo()")
public void after(JoinPoint joinPoint) {
    System.out.println("[Aspect1] after advise");
}

}

Add a test Controller. This Controller has only one method, but it will act differently depending on the value of the parameter: Either return an object normally or throw an exception (because we’re testing the @afterthrowing advice).

package test;

import test.exception.TestException;

import org.springframework.http.HttpStatus;

import org.springframework.web.bind.annotation.*;

@RestController

@RequestMapping(value = “/aop”)

public class AopTestController {

@ResponseStatus(HttpStatus.OK) @RequestMapping(value = "/test", method = RequestMethod.GET) public Result test(@RequestParam boolean throwException) { // case 1 if (throwException) { System.out.println("throw an exception"); throw new TestException("mock a server exception"); } // case 2 System.out.println("test OK"); return new Result() {{ this.setId(111); this.setName("mock a Result"); }}; } public static class Result { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}

}

Test normal condition in the browser directly type the following URL, enter:

http://192.168.142.8:7070/aop…

We should see the output as follows:

[Aspect1] around advise 1

[Aspect1] before advise

test OK

[Aspect1] around advise2

[Aspect1] after advise

[Aspect1] afterReturning advise

To test the exception, type the following URL directly into the browser and press enter:

http://192.168.142.8:7070/aop…

We should see the output as follows:

[Aspect1] around advise 1

[Aspect1] before advise

throw an exception

[Aspect1] after advise

[Aspect1] afterThrowing advise

Conclusion When a method is intercepted by only one aspect class, advice inside the aspect class is executed in the following order:

Normal: One-OK

Exception: One-Exception

Case two: The same method is intercepted by multiple Aspect classes, for example, by two Aspect classes. In some cases, it is possible for two different aspect classes, regardless of whether their advice uses the same pointcut or different pointcuts, to have the same method intercepted by more than one aspect class. In this case, in what order is the advice executed in the multiple Aspect classes? Please look at:

The Pointcut class remains the same and a new aspect class Package Test is added;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;

@Component

@Aspect

public class Aspect2 {

@Before(value = "test.PointCuts.aopDemo()")
public void before(JoinPoint joinPoint) {
    System.out.println("[Aspect2] before advise");
}

@Around(value = "test.PointCuts.aopDemo()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
    System.out.println("[Aspect2] around advise 1");
    pjp.proceed();
    System.out.println("[Aspect2] around advise2");
}

@AfterReturning(value = "test.PointCuts.aopDemo()")
public void afterReturning(JoinPoint joinPoint) {
    System.out.println("[Aspect2] afterReturning advise");
}

@AfterThrowing(value = "test.PointCuts.aopDemo()")
public void afterThrowing(JoinPoint joinPoint) {
    System.out.println("[Aspect2] afterThrowing advise");
}

@After(value = "test.PointCuts.aopDemo()")
public void after(JoinPoint joinPoint) {
    System.out.println("[Aspect2] after advise");
}

}

The test Controller is going to be the same as the Controller up here. But now both AspectT1 and AspectT2 will intercept methods in this Controller.

Let’s continue testing!

Test normal condition in the browser directly type the following URL, enter:

http://192.168.142.8:7070/aop…

We should see the output as follows:

[Aspect2] around advise 1

[Aspect2] before advise

[Aspect1] around advise 1

[Aspect1] before advise

test OK

[Aspect1] around advise2

[Aspect1] after advise

[Aspect1] afterReturning advise

[Aspect2] around advise2

[Aspect2] after advise

[Aspect2] afterReturning advise

But at this point, I can’t say for certain that AspectT2 will execute before AspectT1. Don’t believe it? If you reboot the server and try again, you might see something like this:

[Aspect1] around advise 1

[Aspect1] before advise

[Aspect2] around advise 1

[Aspect2] before advise

test OK

[Aspect2] around advise2

[Aspect2] after advise

[Aspect2] afterReturning advise

[Aspect1] around advise2

[Aspect1] after advise

[Aspect1] afterReturning advise

That is, in this case, the execution order of AspectT1 and AspectT2 is unknown. So what’s the solution? Don’t worry, the solution will be given below.

To test the exception, type the following URL directly into the browser and press enter:

http://192.168.142.8:7070/aop…

We should see the output as follows:

[Aspect2] around advise 1

[Aspect2] before advise

[Aspect1] around advise 1

[Aspect1] before advise

throw an exception

[Aspect1] after advise

[Aspect1] afterThrowing advise

[Aspect2] after advise

[Aspect2] afterThrowing advise

Similarly, if you restart the server and test it again, you might see something like this:

[Aspect1] around advise 1

[Aspect1] before advise

[Aspect2] around advise 1

[Aspect2] before advise

throw an exception

[Aspect2] after advise

[Aspect2] afterThrowing advise

[Aspect1] after advise

[Aspect1] afterThrowing advise

In other words, the execution order of AspectT1 and AspectT2 in exceptional cases is also undetermined.

So in case two, how do you specify the order in which each aspect is executed? There are two ways to do this:

Org. Springframework. Core. Ordered interface, realize its getOrder () method to add @ Order annotation aspect, the called the annotation: Org. Springframework. Core. The annotation. The Order no matter which of the above methods, are the smaller the value aspect, the first execution. For example, we added the @Order annotation for APSECT1 and AspectT2, respectively, as follows:

@Order(5)

@Component

@Aspect

public class Aspect1 {

// ...

}

@Order(6)

@Component

@Aspect

public class Aspect2 {

// ...

}

With this modification, advice in AspectT1 is guaranteed to be executed before advice in AspectT2 in any case. As shown in the figure below: Two-OK

Note that if two identical advice(for example, two @Before) are defined for the same pointcut in the same Aspect class, the order of execution of the two advice cannot be determined. Even if you annotate the two advice with @Order, this will not work. Keep that in mind.

For the @around advice, whether or not it returns a value, it must be inside the method, calling pjp.proceed(); Otherwise, the interface in the Controller will not have a chance to be executed, so the @Before advice will not be fired. For example, let’s assume that the normal execution order is “aspect2-> apsect1-> controller”. If we use pjp.proceed() in @around in aspect1; Delete it, and we should see output like this:

[Aspect2] around advise 1

[Aspect2] before advise

[Aspect1] around advise 1

[Aspect1] around advise2

[Aspect1] after advise

[Aspect1] afterReturning advise

[Aspect2] around advise2

[Aspect2] after advise

[Aspect2] afterReturning advise

As you can see from the results, the interface in Controller is not executed, and the @Before advice in AspectT1 is not executed.

Resources for Spring 4.3.2. The RELEASE of official data: http://docs.spring.io/spring/… Among them, the execution order of AOP chapters as follows: http://docs.spring.io/spring/… Advice ordering

What happens when multiple pieces of advice all want to run at the same join point?

Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution.

The highest precedence advice runs first “on the way in” (so given two pieces of before advice, the one with highest precedence runs first).

“On the way out” from a join point, the highest precedence advice runs last (so given two pieces of after advice, the one with the highest precedence will run second).

When two pieces of advice defined in different aspects both need to run at the same join point,

unless you specify otherwise the order of execution is undefined.

You can control the order of execution by specifying precedence.

This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation.

Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.

When two pieces of advice defined in the same aspect both need to run at the same join point,

the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes).

Consider collapsing such advice methods into one advice method per join point in each aspect class,

or refactor the pieces of advice into separate aspect classes – which can be ordered at the aspect level.

        <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e44c3c0e64.css" rel="stylesheet">
            </div>