“This is the 23rd day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

The most powerful feature of Spring is IOC/AOP. Today we will take a look at Spring AOP common annotations and execution order.

Common annotations to Spring Aop

Let’s start by reviewing some common annotations used in Spring Aop:

  • @before Pre-notification: the target method is executed Before
  • @after Post-notification: execute After target method (always execute)
  • Notification after return: Execution before completion of execution method (exception not executed)
  • @afterthrowing Exception notification: Executed after an exception occurs
  • @around Wrap notification: Execute Around the target method

Q&A

You must know about Spring. How does Spring Boot or Spring Boot 2 affect Aop execution order?

2. Tell me about the pitfalls you have encountered in AOP.

The sample code

Let’s start by quickly building a Spring AOP demo to discuss some of the details of Spring AOP.

The configuration file

In order to facilitate me to directly use spring-boot for quick project construction, you can use the spring-boot project quick creation function of IDEA or go to start.spring. IO to quickly create a spring-boot application. (Because I often manually go to the Internet to post some dependency, dependency conflict service startup failure and other problems).


plugins {
    id 'org.springframework.boot' version '2.6.3'
    id 'io.spring.dependency-management' version '1.0.11. RELEASE'
    id 'java'
}

group 'io.zhengsh'
version 1.0 the SNAPSHOT ' '

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
    maven { url 'https://repo.spring.io/snapshot'}} dependencies {#} dependencies {#'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-aop'
    
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}
Copy the code

Interface class

First we need to define an interface. Here we can revisit the JDK’s choice of default proxy implementation:

If the target object implements the interface, the JDK dynamic proxy is used by default. If the target object implements the interface, the Cglib proxy is used

This piece of logic in DefaultAopProxyFactory you are interested can go to see.

public interface CalcService {

    public int div(int x, int y);
}
Copy the code

The implementation class

Here we do a simple division operation, can simulate normal can easily simulate errors.

@Service
public class CalcServiceImpl implements CalcService {

    @Override
    public int div(int x, int y) {
        int result = x / y;
        System.out.println("====> CalcServiceImpl was called and our calculation is:" + result);
        returnresult; }}Copy the code

Aop interceptors

To declare an interceptor, we need to add @aspect and @Component to the current object. I’ve only added one before.

I didn’t really understand this part at first either, but I didAspectThe definition of annotations is clear to me

There is no definition of a Bean at all. So let’s just add a couple of notes. Add the @enableAspectJAutoProxy annotation to the configuration class if you need to turn on Aop support when testing.

In fact, Aop is used in three steps: (1) define the Aspect definition, (2) define the Pointcut definition, (3) define the specific notification, such as @after, @before, etc.

@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* io.zhengsh.spring.service.impl.. *. * (..) )"
    public void divPointCut(a) {}@Before("divPointCut()")
    public void beforeNotify(a) {
        System.out.println("----===>> @before I am pre-notification");
    }

    @After("divPointCut")
    public void afterNotify(a) {
        System.out.println("----===>> @after I am a post-notification");
    }

    @AfterReturning("divPointCut")
    public void afterReturningNotify(a) {
        System.out.println("----===>> @afterreturning I am pre-notification");
    }

    @AfterThrowing("divPointCut")
    public void afterThrowingNotify(a) {
        System.out.println("----===>> @afterthrowing I am an exception notification");
    }

    @Around("divPointCut")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object retVal;
        System.out.println("----===>> @around surround notification before AAA");
        retVal = proceedingJoinPoint.proceed();
        System.out.println("----===>> @around surround notification after BBB");
        returnretVal; }}Copy the code

The test class

In fact, my Test class, although using the @test annotation, is more like a main method: as follows:

Perform the conclusion

Results: Spring 4.x, Spring-boot 1.5.9

Can’t rely on now, so can’t experiment

Let me jump to a quick conclusion: Spring 4 does surround notification at the very bottom

Result: Spring 5.3.15 SpringBoot 2.6.3

Multifaceted case

In the case of multiple facets, you can specify the Order by using @order. The smaller the number, the higher the priority. As shown below:

Agent failure scenario

The following scenario causes an AOP proxy to fail, Because we’re essentially executing AServer#a’s MethodInterceptor chain, when we’re executing b() directly from a, it’s essentially the same as this.b(), This will invalidate the proxy of the b() method. This is one of the most common problems we developers encounter during development.

@Service
public class AService {
    
    public void a(a) {
        System.out.println("... a");
        b();
    }
    
    public void b(a) {
        System.out.println("... b"); }}Copy the code