1. 序章

この短いチュートリアルでは、AspectJ。JoinPointインターフェイスとProceedingJoinPointインターフェイスの違いについて学習します。

簡単な説明とコード例で説明します。

2. JoinPoint

JoinPointAspectJインターフェースであり、は、メソッドパラメーター、戻り値、スローされた例外など、特定のジョインポイントで利用可能な状態へのリフレクティブアクセスを提供します。 また、メソッド自体に関するすべての静的情報も提供します。

@ Before @After @AfterThrowing 、および@AfterReturningのアドバイスで使用できます。 これらのポイントカットは、メソッドの実行前、実行後、値を返した後、または例外をスローした後、またはメソッドが値を返した後にそれぞれ起動します。

理解を深めるために、基本的な例を見てみましょう。 まず、ポイントカットを宣言する必要があります。 ArticleServiceクラスからのgetArticleList()のすべての実行として定義します。

@Pointcut("execution(* com.baeldung.ArticleService.getArticleList(..))")
public void articleListPointcut(){ }

次に、アドバイスを定義できます。 この例では、@Beforeを使用します。

@Before("articleListPointcut()")
public void beforeAdvice(JoinPoint joinPoint) {
    log.info(
      "Method {} executed with {} arguments",
      joinPoint.getStaticPart().getSignature(),
      joinPoint.getArgs()
    );
}

上記の例では、 @Before アドバイスを使用して、メソッドの実行をそのパラメーターとともにログに記録します。 同様のユースケースは、コードで発生する例外をログに記録することです。

@AfterThrowing(
  pointcut = "articleListPointcut()",
  throwing = "e"
)
public void logExceptions(JoinPoint jp, Exception e) {
    log.error(e.getMessage(), e);
}

@AfterThrowing のアドバイスを使用することにより、例外が発生した場合にのみログが記録されるようにします。

3. ProceedingJoinPoint

ProceedingJoinPoint は、 JoinPoint の拡張であり、追加の progress()メソッドを公開します。 呼び出されると、コード実行は次のアドバイスまたはターゲットメソッドにジャンプします。コードフローを制御し、さらに呼び出しを続行するかどうかを決定する機能を提供します。

@Around のアドバイスを使用するだけで、メソッドの呼び出し全体を囲むことができます。

@Around("articleListPointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
    Object articles = cache.get(pjp.getArgs());
    if (articles == null) {
        articles = pjp.proceed(pjp.getArgs());
    }
    return articles;
}

上記の例では、@Aroundアドバイスの最も一般的な使用法の1つを示しています。 実際のメソッドは、キャッシュが結果を返さない場合にのみ呼び出されます。 これは、Springキャッシュアノテーションが機能する正確な方法です。

ProceedingJoinPointおよび@Aroundのアドバイスを使用して、例外が発生した場合に操作を再試行することもできます。

@Around("articleListPointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
    try {
        return pjp.proceed(pjp.getArgs());
    } catch (Throwable) {
        log.error(e.getMessage(), e);
        log.info("Retrying operation");
        return pjp.proceed(pjp.getArgs());
    }
}

このソリューションは、たとえば、ネットワークが中断した場合にHTTP呼び出しを再試行するために使用できます。

4. 結論

この記事では、AspectJJoinpointProceedingJoinPointの違いについて学びました。 いつものように、すべてのソースコードはGitHub利用できます。