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

1概要

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

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

2使用法

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

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

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

@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)** で始まります。これは、Spring AOPに何を一致させるかを指示するキーワードです。メソッドの実行、型、メソッドの引数、注釈など、いくつかのポイントカット指示子があります。

3.1 実行

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

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

このポイントカットの例は、 FooDao クラスの findById メソッドの実行と完全に一致します。これはうまくいきますが、それほど柔軟ではありません。

FooDao クラスのすべてのメソッドを一致させたいとします。これらのメソッドは、異なる署名、戻り値の型、および引数を持つことができます。これを実現するために、ワイルドカードを使用することができます。

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

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

3.2 within

前のセクションと同じ結果を得るための別の方法は within PCDを使うことです。

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

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

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

3.3 this target

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

public class FooDao implements BarDao {
    ...
}

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

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

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

@Pointcut("this(org.baeldung.dao.FooDao)")

3.4 args

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

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

このポイントカットは、findで始まり、 Long 型のパラメータが1つだけのメソッドに一致します。メソッドを Long 型のfistパラメータを持つ任意の数のパラメータと一致させる場合は、次の式を使用できます。

@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.baeldung.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 @アノテーション

このPCDは、結合点の件名に与えられた注釈がある結合点へのマッチングを制限します。たとえば、 @ Loggable アノテーションを作成します。

@Pointcut("@annotation(org.baeldung.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とポイントカットの簡単な紹介では、ポイントカット式の使用例をいくつか示しました。

例のフルセットはhttps://github.com/eugenp/tutorials/tree/master/spring-mvc-java[my github project]にあります - これはEclipseベースのプロジェクトなので、インポートは簡単です。そのまま実行します。