Heim  >  Artikel  >  Java  >  Interviewer: Allgemeine Anmerkungen und Ausführungssequenz von Spring Aop

Interviewer: Allgemeine Anmerkungen und Ausführungssequenz von Spring Aop

Java后端技术全栈
Java后端技术全栈nach vorne
2023-08-15 16:32:49811Durchsuche

Vor kurzem, als ich Lebensläufe überarbeitete und Probeinterviews für viele Leute führte, gaben mir einige Freunde Feedback zu Fragen zu Spring AOP-Interviews, und ich werde sie heute stellen.

Das Mächtigste an Spring sind zu Beginn die beiden Kernfunktionen von IOC/AOP. Heute lernen wir die allgemeinen Anmerkungen und die Ausführungssequenz von Spring AOP.

Kernpunkte des Spring-Interviews:

IOC, AOP, Bean-Injektion, Bean-Lebenszyklus, Bean-Zirkelabhängigkeit

Lassen Sie uns zunächst einige häufig verwendete Anmerkungen in Spring Aop überprüfen:

  • @Before Vorabbenachrichtigung: wird vor der Zielmethode ausgeführt @Before 前置通知:目标方法之前执行
  • @After 后置通知:目标方法之后执行(始终执行)
  • @AfterReturning 返回之后通知:执行方法结束之前执行(异常不执行)
  • @AfterThrowing 异常通知:出香异常后执行
  • @Around
@AfterThrowing Ausnahmebenachrichtigung: Wird nach der Weihrauchausnahme ausgeführt

@Around Around-Benachrichtigung: Ausführung der Zielmethode umgeben

🎜🎜🎜🎜🎜🎜FAQ🎜🎜🎜 🎜🎜🎜1. Das müssen Sie Kennen Sie Spring, sprechen wir über die Reihenfolge aller Benachrichtigungen in Aop. Wie wirkt sich Spring Boot oder Spring Boot 2 auf die Ausführungsreihenfolge von Aop aus? 🎜🎜2. Erzählen Sie mir von den Fallstricken, auf die Sie bei AOP gestoßen sind? 🎜

Beispielcode

Lassen Sie uns schnell ein Spring Aop-Demoprogramm erstellen, um einige Details von Spring Aop zu besprechen.

Konfigurationsdatei

Um mir die direkte Verwendung von Spring-Boot für die schnelle Projektkonstruktion zu erleichtern, können Sie die Spring-Boot-Projekt-Schnellerstellungsfunktion von idea verwenden oder zu start.spring.io</codestil></p> 上面去快速创建spring-boot 应用。

因为本人经常手动去网上贴一些依赖导致,依赖冲突服务启动失败等一些问题。

plugins {
    id &#39;org.springframework.boot&#39; version &#39;2.6.3&#39;
    id &#39;io.spring.dependency-management&#39; version &#39;1.0.11.RELEASE&#39;
    id &#39;java&#39;
}

group &#39;io.zhengsh&#39;
version &#39;1.0-SNAPSHOT&#39;

repositories {
    mavenCentral()
    maven { url &#39;https://repo.spring.io/milestone&#39; }
    maven { url &#39;https://repo.spring.io/snapshot&#39; }
}

dependencies {
    # 其实这里也可以不增加 web 配置,为了试验简单,大家请忽略 
    implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-actuator&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-aop&#39;
    
    testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
}

tasks.named(&#39;test&#39;) {
    useJUnitPlatform()
}

接口类

首先我们需要定义一个接口。我们这里可以再来回顾一下 JDK 的默认代理实现的选择:

  • 如果目标对象实现了接口,则默认采用JDK动态代理
  • 如果目标对象没有实现接口,则采用进行动态代理
  • 如果目标对象实现了接口,且强制Cglib,则使用cglib代理

这块的逻辑在 DefaultAopProxyFactory

Da ich einige Abhängigkeiten häufig manuell online poste, treten Abhängigkeitskonflikte auf einige Probleme, wie z. B. ein Dienststartfehler.

public interface CalcService {

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

Schnittstellenklasse

Zuerst müssen wir eine Schnittstelle definieren. Hier können wir die Auswahl der Standard-Proxy-Implementierung von JDK überprüfen:

  • Wenn das Zielobjekt Wenn die Schnittstelle implementiert ist, wird standardmäßig der dynamische JDK-Proxy verwendet
  • Wenn das Zielobjekt die Schnittstelle nicht implementiert, verwenden Sie einen dynamischen Proxy
  • Wenn das Zielobjekt die Schnittstelle implementiert und Cglib erzwingt, verwenden Sie den Cglib-Proxy

Die Logik von Dieses Stück ist inDefaultAopProxyFactory Wenn Sie interessiert sind , Sie können einen Blick darauf werfen.
@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;
    }
}
Implementierungsklasse

🎜Hier führen wir einfach eine Divisionsoperation durch, die den normalen Betrieb simulieren und auch leicht Fehler simulieren kann. 🎜
@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;
    }
}
🎜🎜🎜aop Interceptor🎜🎜🎜🎜Deklarieren Sie einen Interceptor und wir müssen @Aspect und @Component zum aktuellen Objekt hinzufügen. Der Autor ist bisher nur auf eine solche Grube getreten und hat nur eines hinzugefügt. 🎜

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

Interviewer: Allgemeine Anmerkungen und Ausführungssequenz von Spring Aop

这里面根本就没有 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: Allgemeine Anmerkungen und Ausführungssequenz von Spring Aop

执行结论

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

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

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

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

Interviewer: Allgemeine Anmerkungen und Ausführungssequenz von Spring Aop
img

多切面的情况

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

Interviewer: Allgemeine Anmerkungen und Ausführungssequenz von Spring Aop

代理失效场景

下面一种场景会导致 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");
    }

}

Das obige ist der detaillierte Inhalt vonInterviewer: Allgemeine Anmerkungen und Ausführungssequenz von Spring Aop. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:Java后端技术全栈. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen