Interceptor der EJB Version 3.x
Ein Interceptor ist eine Methode, die automatisch aufgerufen wird, wenn die Geschäftsmethoden einer EJB (Enterprise Java Bean) aufgerufen werden oder wenn Lebenszyklusereignisse einer EJB eintreten.
Es gibt drei Arten von Interceptormethoden: Interceptor für Geschäftsmethoden, Interceptor für Timeout-Methoden (die in EJB 3.1 neu sind) und Interceptor für Lebenszykluscallbacks. Interceptor für Geschäftsmethoden werden beim Aufruf einer Geschäftsmethode aufgerufen. Interceptor für Timeout-Methoden werden beim Aufruf einer EJB-Methode "timeout" aufgerufen. Interceptor für Lebenszykluscallbacks werden beim Eintreten von PostConstruct-, PreDestroy-, PrePassivate- oder PostActivate-Lebenszyklusereignissen aufgerufen. Für jeden Interceptortyp kann eine Klasse nur eine einzige Interceptormethode deklarieren. Jede Klasse in einer Klassenhierarchie kann jedoch eine Interceptormethode für jeden Interceptortyp deklarieren. Wenn eine Interceptormethode in einer Unterklasse dieselbe Methode in einer Superklasse überschreibt, wird möglicherweise nur die Methode in der Unterklasse aufgerufen.
Interceptormethoden können auf alle Ressourcen und Komponenten zugreifen, die die zugeordnete Methode aufrufen kann. Außerdem werden Interceptormethoden mit demselben Transaktions- und Sicherheitskontext wie die zugeordnete Methode aufgerufen. Lebenszyklusinterceptormethoden werden mit lokalem Transaktionseinschluss (LTC, Local Transaction Containment) ausgeführt. Ausgenommen sind lediglich Singleton-Session-Beans.
Sie können Interceptormethoden direkt in der EJB-Klasse oder in einer separaten Interceptorklasse deklarieren. Zum Deklarieren von Interceptormethoden in einer separaten Klasse müssen Sie die Interceptorklasse mit einer Annotation oder XML an die EJB binden. Verwenden Sie das folgende Beispiel, um Interceptor mit der Annotation zu deklarieren:
@Interceptors({ClassInterceptor1.class, ClassInterceptor2.class})
public class TestBean { /* ... */ }
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@Interceptors({MethodInterceptor1.class, MethodInterceptor2.class})
public void businessMethod() { /* ... */ }
}
Verwenden Sie das folgende Beispiel, um Interceptor mit dem Implementierungsdeskriptor zu deklarieren:
<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>
Sie können Interceptor auf Klassenebene mithilfe der Annotation "ExcludeClassInterceptors" oder mithilfe des Elements "exclude-class-interceptors" im Implementierungsdeskriptor aus einer Methode ausschließen. Verwenden Sie das folgende Beispiel, um den Interceptor "ClassInterceptor" aus der Methode "businessMethod" auszuschließen.
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@ExcludeClassInterceptors
public void businessMethod() { /* ... */ }
public void businessMethodWithClassInterceptor1() { /* ... */
}
Verwenden Sie das folgende Beispiel, um den Interceptor mithilfe des Implementierungsdeskriptors aus der Methode auszuschließen:
<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>
Gültige Sichtbarkeitseinstellungen für Interceptormethoden sind "public", "protected", "package private" und "private". Interceptormethoden dürfen weder final noch static sein. Interceptor für Geschäftsmethoden und Timeout-Methoden müssen den Rückgabetyp "java.lang.Object", javax.interceptor.InvocationContext als einzigen parameter und eine einzige Throws-Klausel des Typs "java.lang.Exception" haben. Alle Lebenszyklusinterceptor müssen den Rückgabetyp "void" und dürfen keine Throws-Klausel haben. Direkt in der EJB-Klasse deklarierte Lebenszyklusinterceptor dürfen keine Parameter haben. Lebenszyklusinterceptor, die in einer EJB-Superklasse oder in einer Interceptorklasse deklariert sind, müssen javax.interceptor.InvocationContext als einzigen Parameter haben. Timeout-Interceptormethoden und Lebenszyklusinterceptormethoden dürfen keine Anwendungsausnahmen auslösen.
Sie können den Parameter "InvocationContext" einer Interceptormethode verwenden, um Informationen zur aufgerufenen Methode abzurufen. Die Methode "getTarget" gibt die Beaninstanz zurück, die aufgerufen wird. Die Methode "getTimer" ist nur für Interceptor für Timeout-Methoden gültig und gibt den ausgeführten Zeitgeber zurück. Die Methode "getMethod" gibt die Geschäftsschnittstellenmethode zurück, die aufgerufen wird. Die Methode "getParameters" gibt die Parameter zurück, die an die Geschäftsmethode übergeben werden, und die Methode "setParameters" lässt die Änderung der Parameter zu. Die Methode "getContextData" gibt die Datenzuordnung zur aufgerufenen Methode zurück. Die Methode "proceed" ruft schließlich den nächsten Interceptor oder die Zielmethode auf.
Sie können Interceptormethoden mithilfe von Annotationen oder XML deklarieren. Zum Deklarieren einer Interceptormethode mit einer Annotation platzieren Sie die entsprechende AroundInvoke-, AroundTimeout-, PostConstruct-, PreDestroy-, PrePassivate- oder PostActivate-Annotation in der Interceptormethode. Verwenden Sie das folgende Beispiel, um einen Interceptor für Geschäftsmethoden, einen Interceptor für Timeout-Methoden und eine Interceptormethode für PostConstruct-Lebenszyklusereignisse in einer EJB-Klasse mithilfe von Annotationen zu deklarieren.
@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();
}
}
Verwenden Sie das folgende Beispiel, um dieselben Interceptormethoden in einer Interceptorklasse zu deklarieren:
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();
}
}
Alternativ können Sie eine Interceptormethode im Implementierungsdeskriptor mit den Elementen around-invoke, around-timeout, post-construct, pre-destroy, pre-passivate und post-activate deklarieren. Verwenden Sie das folgende Beispiel, um einen Interceptor für Geschäftsmethoden, einen Interceptor für Timeout-Methoden und eine Interceptormethode für PostConstruct-Lebenszyklusereignisse in einer EJB-Klasse und in einer Interceptorklasse mithilfe des Implementierungsdeskriptors zu deklarieren.
<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>
Sie können auch Interceptormethoden in Superklassen deklarieren. Verwenden Sie das folgende Beispiel, um einen PostActivate-Interceptor in einer Beansuperklasse mithilfe von Annotationen zu deklarieren:
public class TestBean extends BeanSuperClass { /* ... */ }
public class BeanSuperClass {
@PostActivate
private void beanSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
Verwenden Sie das folgende Beispiel, um dieselbe Interceptormethode in einer Superklasse einer Interceptorklasse mithilfe von Annotationen zu deklarieren:
public class ClassInterceptor extends InterceptorSuperClass { /* ... */ }
public class InterceptorSuperClass {
@PostActivate
private void interceptorSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
Sie können dieselben Interceptormethoden auch mithilfe des Implementierungsdeskriptors deklarieren. Verwenden Sie das folgende Beispiel, um eine Interceptormethode in den Superklassen einer Bean und einer Interceptorklasse zu deklarieren:
<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>
Sie können Standardinterceptor deklarieren, die für alle Session-Beans und Message-driven Beans in einem Modul gelten. Standardinterceptor können nur im Implementierungsdeskriptor deklariert werden, und sie werden mit einem Element "ejb-name" mit dem Wert "*" angegeben. Verwenden Sie das folgende Beispiel, um einen Standardinterceptor zu deklarieren.
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>DefaultInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
Sie können Standardinterceptor mithilfe der Annotation "ExcludeDefaultInterceptors" oder des Elements "exclude-default-interceptors" in der XML aus einer bestimmten Klasse oder Methode ausschließen. Verwenden Sie die folgenden Beispiele, um Standardinterceptor mithilfe der Annotation auszuschließen:
@ExcludeDefaultInterceptors
public class TestBean { /* ... */ }
public class TestBean2 {
@ExcludeDefaultInterceptors
public void businessMethod() { /* ... */ }
}
Verwenden Sie das folgende Beispiel, um Interceptor mithilfe des Implementierungsdeskriptors auszuschließen:
<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>
Beim Aufruf eines Interceptors für eine Methode werden die Standardinterceptorklassen zuerst aufgerufen, danach die Interceptor auf Klassenebene und zuletzt die Interceptormethoden aus der EJB-Klasse. Für eine einzige Interceptorklassenhierarchie werden die Interceptormethoden immer in der allgemeinsten Superklasse zuerst aufgerufen. Die Standardinterceptorklassen und die Interceptorklassen auf Klassenebene werden in der Reihenfolge aufgerufen, in der sie im Implementierungsdeskriptor oder in der Annotation "Interceptors" angegeben sind. Sie können diese Reihenfolge überschreiben, indem Sie die vollständige Liste der Standardinterceptor und die Interceptor auf Klassenebene im Element "interceptor-order" des Implementierungsdeskriptors angeben.
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<!--
Die Standardreihenfolge ist:
1. DefaultInterceptor
2. ClassInterceptor1
3. ClassInterceptor2
Die folgende Zeilengruppe überschreibt die Standardreihenfolge.
-->
<interceptor-order>
<interceptor-class>ClassInterceptor2</interceptor-class>
<interceptor-class>DefaultInterceptor</interceptor-class>
<interceptor-class>ClassInterceptor1</interceptor-class>
</interceptor-order>
</interceptor-binding>
</assembly-descriptor>