Interceptores EJB 3.x
Un interceptor es un método al que se llama automáticamente cuando se invocan los métodos de negocio de Enterprise JavaBeans (EJB) o se producen sucesos de ciclo vital de un EJB.
Hay tres tipos de métodos de interceptor: interceptores de métodos de negocio, interceptores de métodos de tiempo de espera (que son nuevos en EJB3.1) e interceptores de devolución de llamada de ciclo vital. Los interceptores de métodos de negocio se invocan sobre la llamada a un método de negocio. Los interceptores de métodos de tiempo de espera se invocan sobre la llamada a un método de tiempo de espera de EJB. Los interceptores de devolución de llamada de ciclo de vida se llaman sobre uno de los sucesos de ciclo vital siguientes: PostConstruct, PreDestroy, PrePassivate o PostActivate. Para cada tipo de interceptor, una clase individual sólo puede declarar un método de interceptor. No obstante, cada clase de una jerarquía de clases puede declarar un método de interceptor para cada tipo de interceptor. Si un método de interceptor de una subclase sustituye al mismo método de una superclase, sólo se puede invocar el método de la subclase.
A los métodos de interceptor se les permite acceder y llamar a todos los recursos y componentes a los que el método asociado puede llamar. Además, los métodos de interceptor se ejecutan con el mismo contexto de transacción y de seguridad que el método asociado. Excepto en el caso de los beans de sesión singleton, los métodos de interceptor de ciclo vital se ejecutan con contenedor de transacciones locales (LTC).
Puede declarar los métodos de interceptor directamente en la clase EJB o en una clase de interceptor independiente. Para declarar los métodos interceptores en una clase distinta, debe enlazar la clase de interceptor al EJB mediante una anotación o XML. Utilice el siguiente ejemplo para declarar interceptores utilizando la anotación:
@Interceptors({ClassInterceptor1.class, ClassInterceptor2.class})
public class TestBean { /* ... */ }
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@Interceptors({MethodInterceptor1.class, MethodInterceptor2.class})
public void businessMethod() { /* ... */ }
}
Utilice el siguiente ejemplo para declarar interceptores utilizando el descriptor de despliegue:
<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>
Puede excluir interceptores a nivel de clase de un método mediante la anotación ExcludeClassInterceptors o el elemento exclude-class-interceptors del descriptor de despliegue. Utilice el ejemplo siguiente para excluir el interceptor ClassInterceptor del método businessMethod.
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@ExcludeClassInterceptors
public void businessMethod() { /* ... */ }
public void businessMethodWithClassInterceptor1() { /* ... */
}
Utilice el ejemplo siguiente para excluir el interceptor del método utilizando el descriptor de despliegue:
<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>
Los métodos de interceptor pueden tener visibilidad pública, protegida, privada de paquete o privada. Los métodos de interceptor no deben ser finales ni estáticos. Los interceptores de métodos de negocio e interceptores de métodos de tiempo de espera deben tener un tipo de retorno java.lang.Object, un único parámetro de javax.interceptor.InvocationContext y un solo tipo de cláusula throws de java.lang.Exception. Todos los interceptores de ciclo vital deben tener un tipo de retorno vacío y no deben tener una cláusula throws. Los interceptores de ciclo vital declarados directamente en la clase EJB no deben tener parámetros; los interceptores de ciclo vital declarados en un superclase EJB o en una clase de interceptor deben tener un solo parámetro de javax.interceptor.InvocationContext. Los métodos de interceptor de tiempo de espera y los métodos de interceptor de ciclo vital no deben lanzar excepciones de aplicación.
Puede utilizar el parámetro InvocationContext de un método de interceptor para obtener información sobre el método que se invoca. El método getTarget devuelve la instancia del bean que se invoca. El método getTimer sólo es aplicable a interceptores de método de tiempo de espera y devuelve el temporizador que se está ejecutando. El método getMethod devuelve el método de la interfaz empresarial que se está invocando. El método getParameters devuelve los parámetros que se pasan al método de negocio y el método setParameters permite modificar los parámetros. El método getContextData devuelve la asociación de datos con el método que se invoca. Por último, el método proceed invoca el interceptor siguiente o el método de destino.
Puede declarar métodos de interceptor utilizando anotaciones o XML. Para declarar un método de interceptor utilizando una anotación, coloque en el método de interceptor la anotación adecuada de las siguientes: AroundInvoke, AroundTimeout, PostConstruct, PreDestroy, PrePassivate o PostActivate. Utilice el siguiente ejemplo para declarar un interceptor de método de negocio, un interceptor de método de tiempo de espera y un método de interceptor de ciclo vital PostConstruct en una clase EJB utilizando anotaciones.
@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();
}
}
Utilice el siguiente ejemplo para declarar los mismos métodos de interceptor en una clase de interceptor.
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();
}
}
Como alternativa, puede declarar un método de interceptor en el descriptor de despliegue con los elementos around-invoke, around-timeout, post-construct, pre-destroy, pre-passivate y post-activate. Utilice el siguiente ejemplo para declarar un interceptor de método de negocio, un interceptor de método de tiempo de espera y un método de interceptor de ciclo vital PostConstruct en una clase EJB y una clase de interceptor utilizando el descriptor de despliegue.
<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>
También puede declarar métodos de interceptor en superclases. Utilice el ejemplo siguiente para declarar un interceptor PostActivate en una superclase de bean utilizando anotaciones:
public class TestBean extends BeanSuperClass { /* ... */ }
public class BeanSuperClass {
@PostActivate
private void beanSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
Utilice el siguiente ejemplo para declarar el mismo método de interceptor en una superclase de una clase de interceptor utilizando anotaciones:
public class ClassInterceptor extends InterceptorSuperClass { /* ... */ }
public class InterceptorSuperClass {
@PostActivate
private void interceptorSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
También puede declarar los mismos métodos de interceptor utilizando el descriptor de despliegue. Utilice el ejemplo siguiente para declarar un método de interceptor en las superclases de una clase de bean e interceptor:
<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>
Puede declarar los interceptores predeterminados que se aplican a todos los beans de sesión y controlados por mensaje en un módulo. Los interceptores predeterminados sólo se pueden declarar en el descriptor de despliegue y se especifican utilizando un ejb-name "*". Utilice el siguiente ejemplo para declarar un interceptor predeterminado.
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>DefaultInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
Puede excluir interceptores predeterminados a partir de una clase o método específicos mediante la anotación ExcludeDefaultInterceptors o el elemento exclude-default-interceptors en XML. Utilice los ejemplos siguientes para excluir interceptores predeterminados utilizando la anotación:
@ExcludeDefaultInterceptors
public class TestBean { /* ... */ }
public class TestBean2 {
@ExcludeDefaultInterceptors
public void businessMethod() { /* ... */ }
}
Utilice el siguiente ejemplo para excluir interceptores predeterminados utilizando el descriptor de despliegue:
<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>
Cuando se invocan interceptores para un método, las clases de interceptor predeterminado se invocan en primer lugar, los interceptores a nivel de clase se invocan a continuación y por último se invocan los métodos de interceptores de la clase EJB. Para una jerarquía de clases de un solo interceptor, los métodos de interceptor siempre se invocan en la superclase más general en primer lugar. Las clases de interceptor predeterminado y a nivel de clase se invocan en el orden especificado en el descriptor de despliegue o la anotación Interceptores. Puede alterar temporalmente este orden especificando la lista completa de interceptores predeterminados y a nivel de clase en el elemento interceptor-order en el descriptor de despliegue.
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<!--
El orden predeterminado sería:
1. DefaultInterceptor
2. ClassInterceptor1
3. ClassInterceptor2
La stanza siguiente prevalece sobre la ordenación predeterminada.
-->
<interceptor-order>
<interceptor-class>ClassInterceptor2</interceptor-class>
<interceptor-class>DefaultInterceptor</interceptor-class>
<interceptor-class>ClassInterceptor1</interceptor-class>
</interceptor-order>
</interceptor-binding>
</assembly-descriptor>