Home >Java >JavaInterview questions >Interviewer: Spring Aop common annotations and execution sequence

Interviewer: Spring Aop common annotations and execution sequence

Java后端技术全栈
Java后端技术全栈forward
2023-08-15 16:32:49894browse

Recently, when I was revising resumes and doing mock interviews for many people, some friends gave me feedback on Spring AOP interview questions, and I will ask them today.

The most powerful thing about Spring at the beginning is the two core functions of IOC/AOP. Today we will learn about the common annotations and execution sequence of Spring AOP.

Spring interview core points:

IOC, AOP, Bean injection, Bean life cycle, Bean circular dependency

First of all we Let’s review some commonly used annotations in Spring Aop:

  • @Before Pre-notification: Execute before the target method
  • @After Post notification: executed after the target method (always executed)
  • @AfterReturning Post notification: execution method ends Execute before (not executed if exception occurs)
  • @AfterThrowing Exception notification: Execute after exception
  • @Around Around notification: Around target method execution

##FAQ

1. You must know Spring. Let’s talk about the order of all notifications of Aop. How does Spring Boot or Spring Boot 2 affect the execution order of aop?

2. Tell us about the pitfalls you encountered in AOP?

Sample code

Let’s quickly build a demo program of spring aop to discuss spring together Some details in aop.

Configuration file

For the convenience, I directly use spring-boot for quick projects To build, 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 post some dependencies on the Internet, there are some problems such as dependency conflicts and service startup failure.

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-SNAPSHOT'

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
    maven { url 'https://repo.spring.io/snapshot' }
}

dependencies {
    # 其实这里也可以不增加 web 配置,为了试验简单,大家请忽略 
    implementation '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()
}

Interface class

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

  • If the target object implements the interface, the JDK dynamic proxy is used by default
  • If the target object does not implement the interface, use dynamic proxy
  • If the target object implements the interface and Cglib is forced, use cglib proxy

The logic of this piece is in DefaultAopProxyFactory If you are interested, you can take a look.

public interface CalcService {

    public int div(int x, int y);
}

Implementation class

Here we will simply do a division operation, which can simulate normal or easy errors.

@Service
public class CalcServiceImpl implements CalcService {

    @Override
    public int div(int x, int y) {
        int result = x / y;
        System.out.println("====> CalcServiceImpl 被调用了,我们的计算结果是:" + result);
        return result;
    }
}

aop interceptor

#To declare an interceptor, we need to add @Aspect and @Component to the current object. The author has only stepped on it before. Only one such pit has been added.

其实这块我刚开始也不是很理解,但是我看了 Aspect 注解的定义我就清楚了

Interviewer: Spring Aop common annotations and execution sequence

这里面根本就没有 Bean 的定义。所以我们还是乖乖的加上两个注解。

还有就是如果当测试的时候需要开启Aop 的支持为配置类上增加@EnableAspectJAutoProxy 注解。

其实 Aop 使用就三个步骤:

  • 定义 Aspect 定义切面
  • 定义 Pointcut 就是定义我们切入点
  • 定义具体的通知,比如: @After, @Before 等。
@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* io.zhengsh.spring.service.impl..*.*(..))")
    public void divPointCut() {

    }

    @Before("divPointCut()")
    public void beforeNotify() {
        System.out.println("----===>> @Before 我是前置通知");
    }

    @After("divPointCut")
    public void afterNotify() {
        System.out.println("----===>> @After  我是后置通知");
    }

    @AfterReturning("divPointCut")
    public void afterReturningNotify() {
        System.out.println("----===>> @AfterReturning 我是前置通知");
    }

    @AfterThrowing("divPointCut")
    public void afterThrowingNotify() {
        System.out.println("----===>> @AfterThrowing 我是异常通知");
    }

    @Around("divPointCut")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object retVal;
        System.out.println("----===>> @Around 环绕通知之前 AAA");
        retVal = proceedingJoinPoint.proceed();
        System.out.println("----===>> @Around 环绕通知之后 BBB");
        return retVal;
    }
}

测试类

其实我这个测试类,虽然用了 @Test 注解,但是我这个类更加像一个 main 方法把:如下所示:

Interviewer: Spring Aop common annotations and execution sequence

执行结论

结果记录:spring 4.x, spring-boot 1.5.9

无法现在依赖,所以无法试验

我直接说一下结论:Spring 4 中环绕通知是在最里面执行的

结果记录:spring 版本5.3.15 springboot 版本2.6.3

Interviewer: Spring Aop common annotations and execution sequence
img

多切面的情况

多个切面的情况下,可以通过@Order指定先后顺序,数字越小,优先级越高。如下图所示:

Interviewer: Spring Aop common annotations and execution sequence

代理失效场景

下面一种场景会导致 aop 代理失效,因为我们在执行 a 方法的时候其实本质是执行 AServer#a 的方法拦截器(MethodInterceptor)链, 当我们在 a 方法内直接执行b(), 其实本质就相当于 this.b() , 这个时候由执行 a方法是调用到 a 的原始对象相当于是 this 调用,那么会导致 b() 方法的代理失效。这个问题也是我们开发者在开发过程中最常遇到的一个问题。

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

}

The above is the detailed content of Interviewer: Spring Aop common annotations and execution sequence. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:Java后端技术全栈. If there is any infringement, please contact admin@php.cn delete