CDIインターセプターとSpring AspectJ
1前書き
インターセプターパターンは通常、アプリケーションに新しい分野横断的な機能やロジックを追加するために使用され、多数のライブラリで強力なサポートを提供します。
この記事では、これら2つの主要なライブラリーについて説明します。
CDIインターセプターとSpring AspectJ。
2 CDIインターセプタープロジェクトの設定
CDIはJava EEで正式にサポートされていますが、Java SE環境でCDIを使用するためのサポートを提供する実装もあります。
Weld
は、Java SEでサポートされているCDI実装の一例と見なすことができます。
CDIを使用するには、WeldライブラリをPOMにインポートする必要があります。
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>2.3.5.Final</version>
</dependency>
最新のWeldライブラリはhttps://mvnrepository.com/artifact/org.jboss.weld.se/weld-se-core[Maven]リポジトリにあります。
それでは、単純なインターセプターを作成しましょう。
3 CDIインターセプター
の紹介
インターセプトする必要があるクラスを指定するために、インターセプターバインディングを作成しましょう:
@InterceptorBinding
@Target( { METHOD, TYPE } )
@Retention( RUNTIME )
public @interface Audited {
}
インターセプターバインディングを定義したら、実際のインターセプター実装を定義する必要があります。
@Audited
@Interceptor
public class AuditedInterceptor {
public static boolean calledBefore = false;
public static boolean calledAfter = false;
@AroundInvoke
public Object auditMethod(InvocationContext ctx) throws Exception {
calledBefore = true;
Object result = ctx.proceed();
calledAfter = true;
return result;
}
}
すべての
@ AroundInvoke
メソッドは、
javax.interceptor.InvocationContext
引数を取り、
java.lang.Object
を返し、
Exception
をスローすることがあります。
そのため、新しい
@ Audit
インタフェースを使用してメソッドに注釈を付けると、
auditMethod
が最初に呼び出され、その後で初めてターゲットメソッドも実行されます。
4 CDIインターセプターを適用する
作成したインターセプターを何らかのビジネスロジックに適用しましょう。
public class SuperService {
@Audited
public String deliverService(String uid) {
return uid;
}
}
このシンプルなサービスを作成し、傍受したいメソッドに
@ Audited
アノテーションを付けました。
CDIインターセプタを有効にするには、
META-INF
ディレクトリにある
beans.xml
ファイルで完全なクラス名を指定する必要があります。
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans__1__2.xsd">
<interceptors>
<class>com.baeldung.interceptor.AuditedInterceptor</class>
</interceptors>
</beans>
インターセプターが実際に動作したことを検証するために、次のテストを実行しましょう。
public class TestInterceptor {
Weld weld;
WeldContainer container;
@Before
public void init() {
weld = new Weld();
container = weld.initialize();
}
@After
public void shutdown() {
weld.shutdown();
}
@Test
public void givenTheService__whenMethodAndInterceptorExecuted__thenOK() {
SuperService superService = container.select(SuperService.class).get();
String code = "123456";
superService.deliverService(code);
Assert.assertTrue(AuditedInterceptor.calledBefore);
Assert.assertTrue(AuditedInterceptor.calledAfter);
}
}
このクイックテストでは、最初にコンテナからBean
SuperService
を取得し、次にその上でビジネスメソッド
deliverService
を呼び出して、インターセプタ
AuditedInterceptor
が実際にその状態変数を検証することによって呼び出されたことを確認します。
また、
@ Before
および
@ After
アノテーション付きメソッドがあり、それぞれWeld containerを初期化してシャットダウンします。
5 CDIに関する考慮事項
CDIインターセプターの以下の利点を指摘できます。
-
Java EE仕様の標準機能です
-
一部のCDI実装ライブラリはJava SEで使用できます
-
当社が第三者に対して厳しい制限を課している場合に使用可能
図書館
CDIインターセプターの欠点は次のとおりです。
-
ビジネスロジックを持つクラスとインターセプターの間の密接な結合
-
プロジェクトでどのクラスがインターセプトされているのかわかりにくい
-
メソッドのグループにインターセプターを適用するための柔軟なメカニズムの欠如
6. 春のアスペクトJ
SpringはAspectJシンタックスを使った同様のインターセプタ機能の実装をサポートします。
まず、次のSpringとAspectJの依存関係をPOMに追加する必要があります。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
Spring context
、https://mvnrepository.com/artifact/org.aspectj/aspectjweaver[aspectjweaver]の最新版はMavenリポジトリ
AspectJアノテーション構文を使って簡単なアスペクトを作成することができます:
@Aspect
public class SpringTestAspect {
@Autowired
private List accumulator;
@Around("execution(** com.baeldung.spring.service.SpringSuperService.** (..))")
public Object auditMethod(ProceedingJoinPoint jp) throws Throwable {
String methodName = jp.getSignature().getName();
accumulator.add("Call to " + methodName);
Object obj = jp.proceed();
accumulator.add("Method called successfully: " + methodName);
return obj;
}
}
SpringSuperService
クラスのすべてのメソッドに適用されるアスペクトを作成しました。これは、簡単にするために次のようになります。
public class SpringSuperService {
public String getInfoFromService(String code) {
return code;
}
}
7. 春のアスペクトJアスペクトの適用
その側面が実際にサービスに適用されることを検証するために、次のユニットテストを書きましょう。
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = { AppConfig.class })
public class TestSpringInterceptor {
@Autowired
SpringSuperService springSuperService;
@Autowired
private List accumulator;
@Test
public void givenService__whenServiceAndAspectExecuted__thenOk() {
String code = "123456";
String result = springSuperService.getInfoFromService(code);
Assert.assertThat(accumulator.size(), is(2));
Assert.assertThat(accumulator.get(0), is("Call to getInfoFromService"));
Assert.assertThat(accumulator.get(1), is("Method called successfully: getInfoFromService"));
}
}
このテストでは、サービスを注入し、メソッドを呼び出して結果を確認します。
設定は次のようになります。
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public SpringSuperService springSuperService() {
return new SpringSuperService();
}
@Bean
public SpringTestAspect springTestAspect() {
return new SpringTestAspect();
}
@Bean
public List getAccumulator() {
return new ArrayList();
}
}
ここの
@ EnableAspectJAutoProxy
アノテーションの重要な側面の1つ – これは、AspectJの
@ Aspect
アノテーションでマークされたコンポーネントの処理のサポートを可能にします。これは、SpringのXML要素に見られる機能と同様です。
8 Spring AspectJに関する考慮事項
Spring AspectJを使用する利点のいくつかを指摘しましょう。
-
インターセプタはビジネスロジックから切り離されています
-
インターセプターは依存性注入から利益を得ることができます
-
インターセプターはそれ自体にすべての構成情報を持っています
-
新しいインターセプターを追加しても既存のコードを増強する必要はない
-
インターセプターはどの方法を選択するための柔軟なメカニズムを持っています
傍受
** Java EEがなくても使用可能
そしてもちろん、いくつかの欠点もあります。
-
インターセプターを開発するためにはAspectJの構文を知る必要があります
-
AspectJインターセプターの学習曲線は、
CDIインターセプター
9 CDIインターセプターVS Spring AspectJ
現在のプロジェクトでSpringを使用している場合は、Spring AspectJを検討するのが良い選択です。
本格的なアプリケーションサーバーを使用している場合、またはプロジェクトがSpring(またはGoogle Guiceなどの他のフレームワーク)を使用しておらず、厳密にJava EEである場合は、CDIインターセプターを選択する以外に何もありません。
10結論
この記事では、CDIインターセプターとSpring AspectJの2つのインターセプター・パターンの実装について説明しました。それぞれ長所と短所を取り上げました。
この記事の例のソースコードはhttps://github.com/eugenp/tutorials/tree/master/cdi[GitHub]のリポジトリにあります。