EJB 3.x インターセプター
インターセプターとは、ある Enterprise JavaBeans (EJB) のビジネス・メソッドが呼び出されるか、またはある EJB のライフサイクル・イベントが発生すると自動的に呼び出されるメソッドのことです。
インターセプター・メソッドには、ビジネス・メソッド・インターセプター、タイムアウト・メソッド・インターセプター (EJB 3.1 での新機能)、およびライフサイクル・コールバック・インターセプターという 3 つの種類があります。 ビジネス・メソッド・インターセプターは、ビジネス・メソッドに対する呼び出しに関して呼び出されます。 タイムアウト・メソッド・インターセプターは、EJB タイムアウト・メソッドに対する呼び出しに関して呼び出されます。 ライフサイクル・コールバック・インターセプターは、PostConstruct、PreDestroy、PrePassivate、または PostActivate の各ライフサイクル・イベントのいずれかに関して呼び出されます。 インターセプターのタイプごとに、個々のクラスでは 1 つのインターセプター・メソッドしか宣言できません。 ただし、1 つのクラス階層内の各クラスでは、インターセプターのタイプごとに 1 つのインターセプター・メソッドを宣言することができます。 あるサブクラス内のあるインターセプター・メソッドがあるスーパークラス内の同じメソッドをオーバーライドした場合、このサブクラス内のそのメソッドだけしか呼び出すことはできません。
インターセプター・メソッドでは、関連付けられたメソッドが呼び出しを許可された、すべてのリソースとコンポーネントへのアクセスとそれらの呼び出しが許可されます。 また、インターセプター・メソッドは、関連付けられたメソッドと同じトランザクションとセキュリティー・コンテキストを使用して実行されます。 singleton セッション Bean を除き、ライフサイクル・インターセプター・メソッドは、ローカル・トランザクション内包 (LTC) を使用して実行されます。
インターセプター・メソッドは、EJB クラス内で直接宣言でき、また別のインターセプター・クラス内で宣言することもできます。 インターセプター・メソッドを別のクラス内で宣言するには、アノテーションまたは XML のいずれかを使用して、EJB にインターセプター・クラスをバインドする必要があります。 アノテーションを使ってインターセプターを宣言するには、次の例を使用します。
@Interceptors({ClassInterceptor1.class, ClassInterceptor2.class})
public class TestBean { /* ... */ }
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@Interceptors({MethodInterceptor1.class, MethodInterceptor2.class})
public void businessMethod() { /* ... */ }
}
デプロイメント記述子を使ってインターセプターを宣言するには、次の例を使用します。
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<interceptor-class>ClassInterceptor1</interceptor-class>
<interceptor-class>ClassInterceptor2</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>TestBean2</ejb-name>
<interceptor-class>ClassInterceptor1</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>TestBean2</ejb-name>
<interceptor-class>MethodInterceptor1</interceptor-class>
<interceptor-class>MethodInterceptor2</interceptor-class>
<method>
<method-name>businessMethod</method-name>
</method>
</interceptor-binding>
</assembly-descriptor>
クラス・レベルのインターセプターは、メソッドから除外できます。これは、ExcludeClassInterceptors アノテーションを使用するか、またはデプロイメント記述子内で exclude-class-interceptors エレメントを使用することによって行います。 インターセプターの ClassInterceptor をメソッドの businessMethod から除外するには、次の例を使用します。
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@ExcludeClassInterceptors
public void businessMethod() { /* ... */ }
public void businessMethodWithClassInterceptor1() { /* ... */
}
デプロイメント記述子を使ってインターセプターをメソッドから除外するには、次の例を使用します。
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean2</ejb-name>
<exclude-class-interceptors>true</exclude-class-interceptors>
<method>
<method-name>businessMethod</method-name>
</method>
</interceptor-binding>
</assembly-descriptor>
インターセプター・メソッドでは、public、protected、package private、または private の可視性を持つことができます。 インターセプター・メソッドは、final または static にしてはなりません。 ビジネス・メソッド・インターセプターとタイムアウト・メソッド・インターセプターには、java.lang.Object の戻りの型、単一パラメーターの javax.interceptor.InvocationContext、および単一の throws 節タイプの java.lang.Exception を指定する必要があります。 ライフサイクル・インターセプターには、すべて void の戻りの型を指定する必要があり、throws 節を指定してはなりません。 EJB クラスで直接宣言されたライフサイクル・インターセプターには、パラメーターを指定してはなりません。また EJB のスーパークラス、またはインターセプター・クラスで宣言されたライフサイクル・インターセプターには、単一パラメーターの javax.interceptor.InvocationContext を指定する必要があります。 タイムアウト・インターセプター・メソッドとライフサイクル・インターセプター・メソッドでは、アプリケーション例外をスローしてはなりません。
呼び出されているメソッドに関する情報を取得するために、インターセプター・メソッドの InvocationContext パラメーターを使用することができます。 getTarget メソッドでは、呼び出されている Bean インスタンスが返されます。 getTimer メソッドは、タイムアウト・メソッド・インターセプターだけに適用可能で、実行されているタイマーを返します。 getMethod メソッドでは、呼び出されているビジネス・インターフェース・メソッドが返されます。 getParameters メソッドでは、ビジネス・メソッドに渡されているパラメーターが返され、setParameters メソッドでは、パラメーターの変更が許可されます。 getContextData メソッドでは、呼び出されているメソッドとデータとの関連が返されます。 最後に proceed メソッドでは、次のインターセプター、またはターゲット・メソッドのいずれが呼び出されます。
インターセプター・メソッドは、アノテーションまたは XML のいずれかを使用して宣言することができます。 アノテーションを使用してインターセプター・メソッドを宣言するには、インターセプター・メソッドに、AroundInvoke、AroundTimeout、PostConstruct、PreDestroy、PrePassivate、または PostActivate のいずれかの中から該当するアノテーションを配置します。 アノテーションを使って EJB クラスでビジネス・メソッド・インターセプター、タイムアウト・メソッド・インターセプター、および PostConstruct ライフサイクル・インターセプター・メソッドを宣言するには、次の例を使用します。
@Interceptors({ClassInterceptor.class})
public class TestBean {
@PostConstruct
private void beanPostConstruct() { /* ... */ }
@AroundInvoke
protected Object beanAroundInvoke(InvocationContext ic) throws Exception {
return ic.proceed();
}
@AroundTimeout
protected Object beanAroundTimeout(InvocationContext ic) throws Exception {
return ic.proceed();
}
}
インターセプター・クラスで同じインターセプター・メソッドを宣言するには、次の例を使用します。
public class ClassInterceptor {
@PostConstruct
private void interceptorPostConstruct(InvocationContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
@AroundInvoke
protected Object interceptorAroundInvoke(InvocationContext ic) throws Exception {
return ic.proceed();
}
@AroundTimeout
protected Object interceptorAroundTimeout(InvocationContext ic) throws Exception {
return ic.proceed();
}
}
代わりに、インターセプター・メソッドは around-invoke、around-timeout、post-construct、pre-destroy、pre-passivate、および post-activate の各エレメントを使用して、デプロイメント記述子内で宣言することもできます。 デプロイメント記述子を使って EJB クラスとインターセプター・クラスでビジネス・メソッド・インターセプター、タイムアウト・メソッド・インターセプター、および PostConstruct ライフサイクル・インターセプター・メソッドを宣言するには、次の例を使用します。
<enterprise-beans>
<session>
<ejb-name>TestBean</ejb-name>
<around-invoke>
<method-name>beanAroundInvoke</method-name>
</around-invoke>
<around-timeout>
<method-name>beanAroundTimeout</method-name>
</around-timeout>
<post-construct>
<lifecycle-callback-method>beanPostConstruct</lifecycle-callback-method>
</post-construct>
</session>
</enterprise-beans>
<interceptors>
<interceptor>
<interceptor-class>ClassInterceptor</interceptor-class>
<around-invoke>
<method-name>interceptorAroundInvoke</method-name>
</around-invoke>
<around-timeout>
<method-name>interceptorAroundTimeout</method-name>
</around-timeout>
<post-construct>
<lifecycle-callback-method>interceptorPostConstruct</lifecycle-callback-method>
</post-construct>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<interceptor-class>ClassInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
スーパークラスでインターセプター・メソッドを宣言することもできます。アノテーションを使って Bean のスーパークラスで PostActivate インターセプターを宣言するには、次の例を使用します。
public class TestBean extends BeanSuperClass { /* ... */ }
public class BeanSuperClass {
@PostActivate
private void beanSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
アノテーションを使ってインターセプター・クラスのスーパークラスで同じインターセプター・メソッドを宣言するには、次の例を使用します。
public class ClassInterceptor extends InterceptorSuperClass { /* ... */ }
public class InterceptorSuperClass {
@PostActivate
private void interceptorSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
デプロイメント記述子を使用して、同じインターセプター・メソッドを宣言することもできます。 Bean とインターセプター・クラスのスーパークラスでインターセプター・メソッドを宣言するには、次の例を使用します。
<enterprise-beans>
<session>
<ejb-name>TestBean</ejb-name>
<post-activate>
<class>BeanSuperClass</class>
<lifecycle-callback-method>beanSuperClassPostActivate</lifecycle-callback-method>
</post-activate>
</session>
</enterprise-beans>
<interceptors>
<interceptor>
<interceptor-class>ClassInterceptor</interceptor-class>
<post-activate>
<class>InterceptorSuperClass</class>
<lifecycle-callback-method>interceptorSuperClassPostActivate</lifecycle-callback-method>
</post-activate>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<interceptor-class>ClassInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
デフォルトのインターセプターを宣言することができ、これはモジュール内にあるすべてのセッションとメッセージ駆動型 Bean に適用されます。 デフォルトのインターセプターは、デプロイメント記述子内でしか宣言できず、「*」の ejb-name を使用して指定します。 デフォルトのインターセプターを宣言するには、次の例を使用します。
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>DefaultInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
デフォルトのインターセプターを特定のクラスまたはメソッドから除外することができます。これは、ExcludeDefaultInterceptors アノテーションを使用するか、または XML 内で exclude-default-interceptors エレメントを使用することによって行います。 アノテーションを使ってデフォルトのインターセプターを除外するには、次の例を使用します。
@ExcludeDefaultInterceptors
public class TestBean { /* ... */ }
public class TestBean2 {
@ExcludeDefaultInterceptors
public void businessMethod() { /* ... */ }
}
デプロイメント記述子を使ってデフォルトのインターセプターを除外するには、次の例を使用します。
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<exclude-default-interceptors>true</exclude-default-interceptors>
</interceptor-binding>
<interceptor-binding>
<ejb-name>TestBean2</ejb-name>
<exclude-default-interceptors>true</exclude-default-interceptors>
<method>
<method-name>businessMethod</method-name>
</method>
</interceptor-binding>
</assembly-descriptor>
あるメソッドのインターセプターが呼び出されると、最初にデフォルトのインターセプター・クラスが呼び出され、次にクラス・レベルのインターセプターが呼び出され、最後に EJB クラスからのインターセプター・メソッドが呼び出されます。 単一のインターセプター・クラス階層の場合、最も汎用的なスーパークラス上のインターセプター・メソッドが、必ず最初に呼び出されます。 デフォルトおよびクラス・レベルのインターセプター・クラスは、デプロイメント記述子または Interceptors アノテーション内で指定された順序で呼び出されます。 この順序付けは、デプロイメント記述子内で interceptor-order エレメントにデフォルトおよびクラス・レベルのインターセプターのすべてのリストを指定することによってオーバーライドできます。
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<!--
デフォルトの順序付けは、次のとおりです。
1. DefaultInterceptor
2. ClassInterceptor1
3. ClassInterceptor2
以下のスタンザにより、デフォルトの順序付けがオーバーライドされます。
-->
<interceptor-order>
<interceptor-class>ClassInterceptor2</interceptor-class>
<interceptor-class>DefaultInterceptor</interceptor-class>
<interceptor-class>ClassInterceptor1</interceptor-class>
</interceptor-order>
</interceptor-binding>
</assembly-descriptor>