ホームページ > Java > &#&面接の質問 > インタビュアー: Spring Aop の共通アノテーションと実行シーケンス

インタビュアー: Spring Aop の共通アノテーションと実行シーケンス

リリース: 2023-08-15 16:32:49
転載
875 人が閲覧しました

最近、履歴書を修正したり、多くの人に模擬面接を行ったりしていたときに、友人が春の AOP 面接の質問についてフィードバックをくれたので、今日質問してみます。

Spring の最初の最も強力な点は、IOC/AOP の 2 つのコア機能です。今日は Spring AOP の一般的なアノテーションと実行シーケンスを一緒に学びましょう。

春のインタビューのコアポイント:

IOC、AOP、Bean インジェクション、Bean ライフサイクル、Bean 循環依存関係

まず第一に、 Spring Aop で一般的に使用されるいくつかのアノテーションを確認してみましょう:

  • @Before 事前通知: ターゲット メソッドの前に実行
  • @After Post notification: 対象メソッドの後に実行 (常に実行)
  • @AfterReturning Post notification: 実行メソッドの終了前に実行 (例外が発生した場合は実行されません)
  • @AfterThrowing 例外通知: 例外後に実行
  • @Around 通知周り: ターゲットメソッド実行周り

FAQ# #1. Spring について知っておく必要があります。Aop のすべての通知の順序について話しましょう。Spring Boot または Spring Boot 2 は AOP の実行順序にどのように影響しますか?

2. AOP で遭遇した落とし穴について教えてください。

サンプル コード

Spring AOP デモ プログラムを簡単に構築して、Spring について一緒に議論しましょう。ああ。

設定ファイル

便宜上、spring-boot を直接使用して、プロジェクトを構築するには、アイデアの Spring-Boot プロジェクトクイック作成機能を使用するか、start.spring.io に移動して Spring-Boot アプリケーションをすばやく作成できます。

私はインターネット上に依存関係を手動で投稿することが多いため、依存関係の競合やサービスの起動失敗などの問題が発生します。

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()
}
ログイン後にコピー

インターフェイス クラス

最初にインターフェイスを定義する必要があります。ここで、JDK のデフォルトのプロキシ実装の選択を確認できます:

  • ターゲット オブジェクトがインターフェイスを実装する場合、デフォルトで JDK 動的プロキシが使用されます
  • ターゲット オブジェクトがインターフェイスを実装していない場合は、動的プロキシを使用します。
  • #ターゲット オブジェクトがインターフェイスを実装しており、Cglib が強制されている場合は、cglib プロキシを使用します
この部分のロジックは

DefaultAopProxyFactory にあります。興味がある場合は、ご覧ください。

public interface CalcService {

    public int div(int x, int y);
}
ログイン後にコピー

実装クラス

ここでは、通常のエラーまたは簡単なエラーをシミュレートできる除算演算を実行します。

@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 インターセプター

#インターセプターを宣言するには、@Aspect と @Component を現在のオブジェクトに追加する必要があります。このような穴は 1 つだけ追加されました。

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

インタビュアー: 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 方法把:如下所示:

インタビュアー: Spring Aop の共通アノテーションと実行シーケンス

执行结论

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

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

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

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

インタビュアー: Spring Aop の共通アノテーションと実行シーケンス
img

多切面的情况

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

インタビュアー: 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");
    }

}
ログイン後にコピー

以上がインタビュアー: Spring Aop の共通アノテーションと実行シーケンスの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:Java后端技术全栈
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート