春のポイントカット式の紹介

春のポイントカット式の概要

1. 概要

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

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

2. 使用法

ポイントカット式は、@Pointcut注釈の値として表示できます。

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

メソッド宣言はpointcut signatureと呼ばれます。 アドバイスアノテーションがそのポイントカットを参照するために使用できる名前を提供します。

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

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


    

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

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

3.1 execution

プライマリSpringPCDはexecutionであり、メソッド実行のジョインポイントと一致します。

@Pointcut("execution(public String org.example.dao.FooDao.findById(Long))")

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

@Pointcut("execution(* org.example.dao.FooDao.*(..))")

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

3.2 within

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

@Pointcut("within(org.example.dao.FooDao)")

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

@Pointcut("within(org.example..*)")

3.3 this and target

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

public class FooDao implements BarDao {
    ...
}

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

@Pointcut("target(org.example.dao.BarDao)")

一方、FooDaoがインターフェイスを実装していない場合、またはproxyTargetClassプロパティがtrueに設定されている場合、プロキシされるオブジェクトはFooDaoのサブクラスになり、thisPCDは利用される:

@Pointcut("this(org.example.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(org.example.aop.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(org.example.aop.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. 結論

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

例の完全なセットはmy github projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。