Interceptores do EJB 3.x
Um interceptor é um método chamado automaticamente quando os métodos de negócios de um Enterprise JavaBeans (EJB) são chamados ou quando eventos de ciclo de vida de um EJB ocorrerem.
Há três tipos de métodos de interceptores: interceptores de método de negócios, interceptores de método de tempo limite (que são novos no EJB 3.1) e interceptores de retorno de chamada do ciclo de vida. Os interceptores de método de negócios são chamados em torno da chamada de um método de negócios. Os interceptores de método de tempo limite são chamados em torno da chamada de um método de tempo limite do EJB. Os interceptores de retorno de chamada de ciclo de vida são chamados em torno de um dos eventos de ciclo de vida PostConstruct, PreDestroy, PrePassivate, ou PostActivate. Para cada tipo de interceptor, uma classe individual pode declarar apenas um método de interceptor. Entretanto, cada classe em uma hierarquia de classes pode declarar um método de interceptor para cada tipo de interceptor. Se um método do interceptor em uma subclasse substituir o mesmo método em uma super-classe, apenas o método na subclasse poderá ser chamado.
Os métodos de interceptores podem acessar e chamar todos os recursos e componentes que o método associado puder chamar. Além disso, os métodos interceptores executam a mesma transação e contexto de segurança como o método associado. Exceto para beans de sessão singleton, os métodos de interceptores de ciclo de vida são executados com a Local Transaction Containment (LTC).
É possível declarar os métodos de interceptores diretamente na classe EJB ou em uma classe de interceptor separada. Para declarar os métodos de interceptor em uma classe separada, você deve ligar a classe interceptora ao EJB usando um anotação ou um XML. Use o seguinte exemplo para declarar interceptores usando a anotação:
@Interceptors({ClassInterceptor1.class, ClassInterceptor2.class})
public class TestBean { /* ... */ }
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@Interceptors({MethodInterceptor1.class, MethodInterceptor2.class})
public void businessMethod() { /* ... */ }
}
Use o seguinte exemplo para declarar interceptores usando o descritor de implementação:
<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>
É possível excluir interceptores no nível de classe de um método usando a anotação ExcludeClassInterceptors ou o elemento exclude-class-interceptors no descritor de implementação. Use o seguinte exemplo para excluir o interceptor, ClassInterceptor, do método, businessMethod.
@Interceptors({ClassInterceptor1.class})
public class TestBean2 {
@ExcludeClassInterceptors
public void businessMethod() { /* ... */ }
public void businessMethodWithClassInterceptor1() { /* ... */
}
Use o seguinte exemplo para excluir o interceptor do método usando o descritor de implementação:
<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>
Os métodos de interceptor podem ter visibilidade pública, protegida, pacote privado ou privada. Os métodos de interceptor não devem ser final ou estático. Os interceptores de método de negócios e os interceptores de método de tempo limite devem ter um tipo de retorno de java.lang.Object, um parâmetro único de javax.interceptor.InvocationContext e um tipo de cláusula de lançamento único de java.lang.Exception. Todos os interceptores de ciclo de vida devem ter um tipo de retorno de anulação e não devem ter cláusulas de lançamentos. Os interceptores de ciclo de vida declarados diretamente na classe EJB não devem ter parâmetros; os interceptores de ciclo de vida declarados em uma superclasse EJB ou em uma classe de interceptor devem ter um parâmetro único de javax.interceptor.InvocationContext. Os métodos de interceptor de tempo limite e os métodos de interceptor de ciclo de vida não devem emitir exceções de aplicativo.
É possível usar o parâmetro InvocationContext de um método de interceptor para obter informações sobre o método que está sendo chamado. O método getTarget retorna a instância do bean que está sendo chamada. O método getTimer é aplicável apenas aos interceptores de método de tempo limite e retorna o timer que está sendo executado. O método getMethod retorna o método de interface de negócios que está sendo chamada. O método getParameters retorna os parâmetros que estão sendo passados para o método de negócios e o método setParameters permite que os parâmetros sejam modificados. O método getContextData retorna os dados associados ao método que está sendo chamado. Por fim, o método de processo chama o próximo interceptor ou o método de destino.
É possível declarar os métodos de interceptor usando as anotações ou o XML. Para declara um método do interceptor usando uma anotação, coloque a anotação AroundInvoke, AroundTimeout, PostConstruct, PreDestroy, PrePassivate ou PostActivate apropriada no método do interceptor. Use o seguinte exemplo para declarar um interceptor de método de negócios, um interceptor de método de tempo limite e um método do interceptor de ciclo de vida PostConstruct em uma classe EJB usando anotações.
@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();
}
}
Use o seguinte exemplo para declarar os mesmos métodos de interceptor em uma classe 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, é possível declarar um método do interceptor no descritor de implementação com os elementos around-invoke, around-timeout, post-construct, pre-destroy, pre-passivatee post-activate. Use o seguinte exemplo para declarar um interceptor de método de negócios, um interceptor de método de tempo limite e um método do interceptor de ciclo de vida PostConstruct em uma classe EJB e em uma classe de interceptor usando o descritor de implementação.
<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>
Também é possível declarar métodos do interceptor nas super classes. Use o seguinte exemplo para declarar o interceptor PostActivate em uma super classe de bean usando anotações:
public class TestBean extends BeanSuperClass { /* ... */ }
public class BeanSuperClass {
@PostActivate
private void beanSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
Use o seguinte exemplo para declarar o mesmo método de interceptor em uma super classe de uma classe de interceptor usando anotações:
public class ClassInterceptor extends InterceptorSuperClass { /* ... */ }
public class InterceptorSuperClass {
@PostActivate
private void interceptorSuperClassPostActivate(InterceptorContext ic) {
try {
ic.proceed();
} catch (Exception ex) { /* ... */ }
}
}
Também é possível declarar os mesmos métodos do interceptor usando o descritor de implementação. Use o seguinte exemplo para declarar um método do interceptor nas super classes de um bean e em uma classe de 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>
É possível declarar interceptores padrão que se aplicam a todos os beans de sessão e acionados por mensagem em um módulo. Os interceptores padrão podem ser declarados apenas no descritor de implementação e eles são especificados usando um ejb-name de "*". Use o seguinte exemplo para declarar um interceptor padrão:
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>DefaultInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
É possível excluir os interceptores padrão de uma classe ou método específico usando a anotação ExcludeDefaultInterceptors ou o elemento exclude-default-interceptors no XML. Use os seguintes exemplos para excluir interceptores padrão usando a anotação:
@ExcludeDefaultInterceptors
public class TestBean { /* ... */ }
public class TestBean2 {
@ExcludeDefaultInterceptors
public void businessMethod() { /* ... */ }
}
Use o seguinte exemplo para excluir os interceptores padrão usando o descritor de implementação:
<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>
Quando os interceptores são chamados para um método, as classes do interceptor padrão são chamadas primeiro, os interceptores no nível da classe são chamados em seguida e os métodos do interceptor a partir da classe EJB são chamados por último. Para uma hierarquia de classe de interceptor única, os métodos do interceptor são sempre chamados primeiro na super classe geral. As classes do interceptor padrão e no nível de classe são chamadas na ordem especificada no descritor de implementação ou na anotação Interceptores. É possível substituir essa ordem ao especificar a lista completa de interceptores padrão e no nível de classe no elemento interceptor-order no descritor de implementação.
<assembly-descriptor>
<interceptor-binding>
<ejb-name>TestBean</ejb-name>
<!--
The default ordering would be:
1. DefaultInterceptor
2. ClassInterceptor1
3. ClassInterceptor2
The following stanza overrides the default ordering.
-->
<interceptor-order>
<interceptor-class>ClassInterceptor2</interceptor-class>
<interceptor-class>DefaultInterceptor</interceptor-class>
<interceptor-class>ClassInterceptor1</interceptor-class>
</interceptor-order>
</interceptor-binding>
</assembly-descriptor>