Spring のポイントカット API

このセクションでは、Spring が重要なポイントカットの概念をどのように処理するかについて説明します。

概念

Spring のポイントカットモデルは、アドバイス型に関係なくポイントカットの再利用を可能にします。同じポイントカットで異なるアドバイスをターゲットにすることができます。

org.springframework.aop.Pointcut インターフェースは中心的なインターフェースであり、アドバイスを特定のクラスとメソッドに向けるために使用されます。完全なインターフェースは次のとおりです。

public interface Pointcut {

	ClassFilter getClassFilter();

	MethodMatcher getMethodMatcher();
}

Pointcut インターフェースを 2 つの部分に分割すると、クラスとメソッドのマッチング部分ときめの細かい構成操作(別のメソッドマッチャーとの「結合」の実行など)を再利用できます。

ClassFilter インターフェースは、ポイントカットを特定のターゲットクラスのセットに制限するために使用されます。matches() メソッドが常に true を返す場合、すべてのターゲットクラスが一致します。次のリストは、ClassFilter インターフェース定義を示しています。

public interface ClassFilter {

	boolean matches(Class clazz);
}

通常、MethodMatcher インターフェースの方が重要です。完全なインターフェースは次のとおりです。

public interface MethodMatcher {

	boolean matches(Method m, Class<?> targetClass);

	boolean isRuntime();

	boolean matches(Method m, Class<?> targetClass, Object... args);
}

matches(Method, Class) メソッドは、このポイントカットがターゲットクラスの特定のメソッドと一致するかどうかをテストするために使用されます。この評価は、AOP プロキシが作成されるときに実行でき、すべてのメソッド呼び出しでのテストの必要性を回避できます。2 つの引数を持つ matches メソッドが指定されたメソッドに対して true を返し、MethodMatcher に対する isRuntime() メソッドが true を返す場合、3 つの引数の一致メソッドがすべてのメソッド呼び出しで呼び出されます。これにより、ポイントカットは、ターゲットアドバイスが開始する直前にメソッド呼び出しに渡された引数を確認できます。

ほとんどの MethodMatcher 実装は静的です。つまり、isRuntime() メソッドは false を返します。この場合、引数が 3 つの matches メソッドは呼び出されません。

可能であれば、ポイントカットを静的にし、AOP フレームワークが AOP プロキシの作成時にポイントカット評価の結果をキャッシュできるようにします。

ポイントカットの操作

Spring は、ポイントカットの操作(特に、ユニオンとインターセクション)をサポートします。

Union は、どちらかのポイントカットが一致するメソッドを意味します。交差とは、両方のポイントカットが一致する方法を意味します。通常、Union はより便利です。org.springframework.aop.support.Pointcuts クラスの静的メソッドを使用するか、同じパッケージの ComposablePointcut クラスを使用して、ポイントカットを作成できます。ただし、AspectJ ポイントカット式の使用は、通常、より簡単なアプローチです。

AspectJ 式ポイントカット

2.0 以降、Spring が使用する最も重要な型のポイントカットは org.springframework.aop.aspectj.AspectJExpressionPointcut です。これは、AspectJ が提供するライブラリを使用して AspectJ ポイントカット式文字列を解析するポイントカットです。

サポートされている AspectJ ポイントカットプリミティブについては、前の章を参照してください。

便利なポイントカットの実装

Spring はいくつかの便利なポイントカット実装を提供します。それらのいくつかを直接使用できます。その他は、アプリケーション固有のポイントカットでサブクラス化されることを目的としています。

静的ポイントカット

静的ポイントカットはメソッドとターゲットクラスに基づいており、メソッドの引数を考慮することはできません。ほとんどの場合、静的ポイントカットで十分であり、最適です。Spring は、メソッドが最初に呼び出されたときに、静的ポイントカットを一度だけ評価できます。その後、各メソッド呼び出しでポイントカットを再度評価する必要はありません。

このセクションの残りの部分では、Spring に含まれる静的ポイントカット実装のいくつかについて説明します。

正規表現のポイントカット

静的ポイントカットを指定する明白な方法の 1 つは、正規表現です。Spring 以外のいくつかの AOP フレームワークがこれを可能にします。org.springframework.aop.support.JdkRegexpMethodPointcut は、JDK の正規表現サポートを使用する汎用正規表現ポイントカットです。

JdkRegexpMethodPointcut クラスを使用すると、パターン文字列のリストを提供できます。これらのいずれかが一致する場合、ポイントカットは true に評価されます。(結果として、結果として生じるポイントカットは、指定されたパターンの結合になります。)

次の例は、JdkRegexpMethodPointcut の使用方法を示しています。

  • Java

  • Kotlin

  • XML

@Configuration
public class JdkRegexpConfiguration {

	@Bean
	public JdkRegexpMethodPointcut settersAndAbsquatulatePointcut() {
		JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
		pointcut.setPatterns(".*set.*", ".*absquatulate");
		return pointcut;
	}
}
@Configuration
class JdkRegexpConfiguration {

	@Bean
	fun settersAndAbsquatulatePointcut() = JdkRegexpMethodPointcut().apply {
		setPatterns(".*set.*", ".*absquatulate")
	}
}
<bean id="settersAndAbsquatulatePointcut"
	  class="org.springframework.aop.support.JdkRegexpMethodPointcut">
	<property name="patterns">
		<list>
			<value>.*set.*</value>
			<value>.*absquatulate</value>
		</list>
	</property>
</bean>

Spring は、RegexpMethodPointcutAdvisor という名前の便利なクラスを提供します。これにより、Advice を参照することもできます(Advice は、アドバイスの前、インターセプト、スローなど)。バックグラウンドでは、Spring は JdkRegexpMethodPointcut を使用しています。RegexpMethodPointcutAdvisor を使用すると、次の例に示すように、1 つの Bean がポイントカットとアドバイスの両方をカプセル化するため、接続が簡単になります。

  • Java

  • Kotlin

  • XML

@Configuration
public class RegexpConfiguration {

	@Bean
	public RegexpMethodPointcutAdvisor settersAndAbsquatulateAdvisor(Advice beanNameOfAopAllianceInterceptor) {
		RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
		advisor.setAdvice(beanNameOfAopAllianceInterceptor);
		advisor.setPatterns(".*set.*", ".*absquatulate");
		return advisor;
	}
}
@Configuration
class RegexpConfiguration {

	@Bean
	fun settersAndAbsquatulateAdvisor(beanNameOfAopAllianceInterceptor: Advice) = RegexpMethodPointcutAdvisor().apply {
		advice = beanNameOfAopAllianceInterceptor
		setPatterns(".*set.*", ".*absquatulate")
	}
}
<bean id="settersAndAbsquatulateAdvisor"
	  class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
	<property name="advice">
		<ref bean="beanNameOfAopAllianceInterceptor"/>
	</property>
	<property name="patterns">
		<list>
			<value>.*set.*</value>
			<value>.*absquatulate</value>
		</list>
	</property>
</bean>

RegexpMethodPointcutAdvisor は、任意の Advice 型で使用できます。

属性駆動型のポイントカット

静的なポイントカットの重要な型は、メタデータ駆動型のポイントカットです。これは、メタデータ属性の値(通常、ソースレベルのメタデータ)を使用します。

動的ポイントカット

動的ポイントカットは、静的ポイントカットよりも評価にコストがかかります。メソッドの引数と静的情報を考慮します。これは、すべてのメソッド呼び出しで評価する必要があり、引数が異なるため結果をキャッシュできないことを意味します。

主な例は、control flow ポイントカットです。

制御フローポイントカット

Spring 制御フローポイントカットは、概念的には AspectJ cflow ポイントカットに似ていますが、強力ではありません。(現在、ポイントカットが別のポイントカットと一致するジョインポイントで実行されるように指定する方法はありません)制御フローポイントカットは、現在の呼び出しスタックと一致します。例: com.mycompany.web パッケージのメソッドまたは SomeCaller クラスによってジョインポイントが呼び出された場合に発生する可能性があります。制御フローポイントカットは、org.springframework.aop.support.ControlFlowPointcut クラスを使用して指定されます。

制御フローのポイントカットは、他の動的なポイントカットよりも、実行時に評価するのに非常に費用がかかります。Java 1.4 では、コストは他の動的ポイントカットの約 5 倍です。

ポイントカットスーパークラス

Spring は、独自のポイントカットを実装するのに役立つ便利なポイントカットスーパークラスを提供します。

静的ポイントカットは最も有用であるため、おそらく StaticMethodMatcherPointcut をサブクラス化する必要があります。これには、抽象メソッドを 1 つだけ実装する必要があります(ただし、他のメソッドをオーバーライドして動作をカスタマイズできます)。次の例は、StaticMethodMatcherPointcut をサブクラス化する方法を示しています。

  • Java

  • Kotlin

class TestStaticPointcut extends StaticMethodMatcherPointcut {

	public boolean matches(Method m, Class targetClass) {
		// return true if custom criteria match
	}
}
class TestStaticPointcut : StaticMethodMatcherPointcut() {

	override fun matches(method: Method, targetClass: Class<*>): Boolean {
		// return true if custom criteria match
	}
}

動的ポイントカット用のスーパークラスもあります。任意のアドバイス型でカスタムポイントカットを使用できます。

カスタムポイントカット

Spring AOP のポイントカットは(AspectJ のような)言語機能ではなく Java クラスであるため、静的または動的にかかわらず、カスタムポイントカットを宣言できます。Spring のカスタムポイントカットは、任意に複雑にすることができます。ただし、可能であれば、AspectJ ポイントカット式言語の使用をお勧めします。

Spring の以降のバージョンは、JAC が提供する「セマンティックポイントカット」のサポートを提供する可能性があります。たとえば、「ターゲットオブジェクトのインスタンス変数を変更するすべてのメソッド」です。