1. 概要

このチュートリアルでは、SpringAOPポイントカット式言語について説明します。

まず、アスペクト指向プログラミングで使用されるいくつかの用語を紹介します。 ジョインポイントは、メソッドの実行や例外の処理など、プログラム実行のステップです。 Spring AOPでは、ジョインポイントは常にメソッドの実行を表します。 ポイントカットは結合点に一致する述語であり、ポイントカット式言語はプログラムでポイントカットを記述する方法です。

2. 使用法

ポイントカット式は、@Pointcutアノテーションの値として表示できます。

@Pointcut("within(@org.springframework.stereotype.Repository *)")
public void repositoryClassMethods() {}

メソッド宣言は、ポイントカットシグニチャと呼ばれます。 これは、アドバイス注釈がそのポイントカットを参照するために使用できる名前を提供します。

@Around("repositoryClassMethods()")
public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
    ...
}

ポイントカット式は、 aop:pointcutタグのexpressionプロパティの値として表示される場合もあります。

<aop:config>
    <aop:pointcut id="anyDaoMethod" 
      expression="@target(org.springframework.stereotype.Repository)"/>
</aop:config>

3. ポイントカット指定子

ポイントカット式は、ポイントカット指定子(PCD)で始まります。これは、SpringAOPに何を一致させるかを指示するキーワードです。 メソッド、タイプ、メソッド引数、または注釈の実行など、いくつかのポイントカット指定子があります。

3.1. 実行

主要なSpringPCDはexecutionであり、メソッド実行の結合点と一致します。

@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))")

このサンプルポイントカットは、FooDaoクラスのfindByIdメソッドの実行と完全に一致します。 これは機能しますが、あまり柔軟ではありません。 FooDao クラスのすべてのメソッドを照合したいとします。これらのメソッドは、異なるシグネチャ、リターンタイプ、および引数を持つ場合があります。 これを実現するために、ワイルドカードを使用できます。

@Pointcut("execution(* com.baeldung.pointcutadvice.dao.FooDao.*(..))")

ここで、最初のワイルドカードは任意の戻り値に一致し、2番目は任意のメソッド名に一致し、(..)パターンは任意の数のパラメーター(ゼロ以上)に一致します。

3.2.

前のセクションと同じ結果を達成する別の方法は、within PCDを使用することです。これにより、特定のタイプの結合ポイントへのマッチングが制限されます。

@Pointcut("within(com.baeldung.pointcutadvice.dao.FooDao)")

com.baeldungパッケージまたはサブパッケージ内の任意のタイプに一致させることもできます。

@Pointcut("within(com.baeldung..*)")

3.3. thisおよびtarget

this は、Bean参照が指定されたタイプのインスタンスである結合ポイントへのマッチングを制限し、 target は、ターゲットオブジェクトが指定されたタイプのインスタンスである結合ポイントへのマッチングを制限します。 前者はSpringAOPがCGLIBベースのプロキシを作成するときに機能し、後者はJDKベースのプロキシが作成されるときに使用されます。 ターゲットクラスがインターフェイスを実装するとします。

public class FooDao implements BarDao {
    ...
}

この場合、Spring AOPはJDKベースのプロキシを使用し、プロキシされるオブジェクトは Proxy クラスのインスタンスであり、 BarDaoを実装するため、 targetPCDを使用する必要があります。 インターフェース:

@Pointcut("target(com.baeldung.pointcutadvice.dao.BarDao)")

一方、 FooDao がインターフェイスを実装していない場合、または proxyTargetClass プロパティがtrueに設定されている場合、プロキシされるオブジェクトはFooDaoおよび this PCDを使用できます:

@Pointcut("this(com.baeldung.pointcutadvice.dao.FooDao)")

3.4. args

このPCDは、特定のメソッド引数を照合するために使用されます。

@Pointcut("execution(* *..find*(Long))")

このポイントカットは、findで始まり、タイプLongのパラメーターが1つしかないすべてのメソッドに一致します。 メソッドを任意の数のパラメーターと一致させたいが、タイプ Long の最初のパラメーターがある場合は、次の式を使用できます。

@Pointcut("execution(* *..find*(Long,..))")

3.5. @target

@target PCD(上記の target PCDと混同しないでください)は、実行中のオブジェクトのクラスに特定のタイプの注釈がある結合点へのマッチングを制限します。

@Pointcut("@target(org.springframework.stereotype.Repository)")

3.6. @args

このPCDは、渡された実際の引数の実行時タイプが指定されたタイプの注釈を持つ結合点へのマッチングを制限します。 @Entityアノテーションが付けられたBeanを受け入れるすべてのメソッドをトレースするとします。

@Pointcut("@args(com.baeldung.pointcutadvice.annotations.Entity)")
public void methodsAcceptingEntities() {}

引数にアクセスするには、アドバイスにJoinPoint引数を指定する必要があります。

@Before("methodsAcceptingEntities()")
public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) {
    logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]);
}

3.7. @within

このPCDは、指定された注釈を持つタイプ内の結合ポイントへのマッチングを制限します。

@Pointcut("@within(org.springframework.stereotype.Repository)")

これは次と同等です:

@Pointcut("within(@org.springframework.stereotype.Repository *)")

3.8. @annotation

このPCDは、ジョインポイントのサブジェクトに指定された注釈があるジョインポイントへのマッチングを制限します。 たとえば、@Loggableアノテーションを作成できます。

@Pointcut("@annotation(com.baeldung.pointcutadvice.annotations.Loggable)")
public void loggableMethods() {}

次に、そのアノテーションでマークされたメソッドの実行をログに記録します。

@Before("loggableMethods()")
public void logMethod(JoinPoint jp) {
    String methodName = jp.getSignature().getName();
    logger.info("Executing method: " + methodName);
}

4. ポイントカット式の組み合わせ

ポイントカット式は、を使用して組み合わせることができます && || 演算子:

@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() {}

@Pointcut("execution(* *..create*(Long,..))")
public void firstLongParamMethods() {}

@Pointcut("repositoryMethods() && firstLongParamMethods()")
public void entityCreationMethods() {}

5. 結論

このSpringAOPとポイントカットの簡単な紹介では、ポイントカット式の使用例をいくつか示しました。

例の完全なセットは、GitHubにあります。