SeamFramework.orgCommunity Documentation

Capítulo 7. Interceptores

7.1. Enlaces de interceptor
7.2. Implementación de interceptores
7.3. Habilitar Interceptores
7.4. Enlaces de interceptor con miembros
7.5. Anotaciones de enlace de múltiples interceptores
7.6. Herencia del tipo de interceptor de enlace
7.7. Uso de @Interceptors

Web Beans reutiliza el interceptor de arquitectura básico de EJB 3.0, extendiendo la funcionalidad en dos direcciones:

La especificación EJB define dos clases de puntos de interceptación:

Un interceptor de método de negocios se aplica a invocaciones de métodos del Web Bean por clientes del Web Bean:

public class TransactionInterceptor {

    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}

Un interceptor de devolución de llamadas de ciclo de vida se aplica a invocaciones de devolución de llamadas de ciclo de vida por el contenedor:

public class DependencyInjectionInterceptor {

    @PostConstruct public void injectDependencies(InvocationContext ctx) { ... }
}

Una clase de interceptor puede interceptar métodos de devolución de llamadas de ciclo de vida y métodos de negocios.

Suponga que deseamos declarar que algunos de nuestros Web Beans son transaccionales. La primera cosa que necesitamos es una anotación de enlace de interceptor para especificar exactamente en cuáles Web Beans estamos interesados:

@InterceptorBindingType

@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}

Ahora podemos especificar con facilidad que nuestro ShoppingCart es un objeto transaccional:

@Transactional

public class ShoppingCart { ... }

O, si preferimos, podemos especificar que sólo un método es transaccional:

public class ShoppingCart {

    @Transactional public void checkout() { ... }
}

Es maravilloso, pero en alguna parte de la línea vamos a tener que implementar realmente el interceptor que proporciona este aspecto de manejo de transacción. Todo lo que debemos hacer es crear un interceptor estándar EJB, y anotar @Interceptor y @Transactional.

@Transactional @Interceptor

public class TransactionInterceptor {
    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}

Todos los interceptores de Web Beans son Web Beans sencillos, y podemos aprovechar las ventajas de inyección de dependencia y administración de ciclo de vida contextual.

@ApplicationScoped @Transactional @Interceptor

public class TransactionInterceptor {
    @Resource Transaction transaction;
    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
    
}

Múltiples Interceptores pueden utilizar el mismo tipo de vinculación de interceptor.

Por último, necesitamos habilitar nuestro interceptor en web-beans.xml.


<Interceptors>
    <tx:TransactionInterceptor/>
</Interceptors
>

¿Por qué el corchete angular permanece?

Bien, la declaración XML resuelve dos problemas:

Por ejemplo, podemos especificar que nuestro interceptor de seguridad se ejecuta antes que nuestro TransactionInterceptor.


<Interceptors>
    <sx:SecurityInterceptor/>
    <tx:TransactionInterceptor/>
</Interceptors
>

O podemos ¡apagarlo en nuestro entorno de prueba!

Suponga que deseamos agregar alguna información adicional a nuestra anotación @Transactional:

@InterceptorBindingType

@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
    boolean requiresNew() default false;
}

Web Beans utilizará el valor de requiresNew para escoger entre dos interceptores, TransactionInterceptor y RequiresNewTransactionInterceptor.

@Transactional(requiresNew=true) @Interceptor

public class RequiresNewTransactionInterceptor {
    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}

Ahora podemos utilizar RequiresNewTransactionInterceptor de esta manera:

@Transactional(requiresNew=true)

public class ShoppingCart { ... }

Pero, ¿qué sucede si sólo tenemos un interceptor y queremos que el administrador ignore el valor de requiresNew al vincular interceptores? Podemos utilizar la anotación @NonBinding:

@InterceptorBindingType

@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
    @NonBinding String[] rolesAllowed() default {};
}

Generalmente utilizamos combinaciones de tipos de interceptores de enlace para vincular múltiples interceptores a un Web Bean. Por ejemplo, la siguiente declaración sería utilizada para enlazar TransactionInterceptor y SecurityInterceptor al mismo Web Bean:

@Secure(rolesAllowed="admin") @Transactional

public class ShoppingCart { ... }

Sin embargo, en casos muy complejos, el mismo interceptor puede especificar una combinación de tipos de interceptor de enlace:

@Transactional @Secure @Interceptor

public class TransactionalSecureInterceptor { ... }

Entonces este interceptor podría estar vinculado al método checkout() mediante cualquiera de las siguientes combinaciones:

public class ShoppingCart {

    @Transactional @Secure public void checkout() { ... }
}
@Secure

public class ShoppingCart {
    @Transactional public void checkout() { ... }
}
@Transactionl

public class ShoppingCart {
    @Secure public void checkout() { ... }
}
@Transactional @Secure

public class ShoppingCart {
    public void checkout() { ... }
}

Una limitación de la compatibilidad del lenguaje de Java para anotaciones es la falta de herencia de anotación. En realidad, las anotaciones deberían tener reutilización incorporada, para permitir a este tipo que funcione:

public @interface Action extends Transactional, Secure { ... }

Bueno, afortunadamente, Web Beans funciona en torno a esta característica de Java. Podemos anotar un interceptor de tipo de enlace con otros tipos de interceptores de enlace. Los enlaces de interceptor son transitivos — cualquier Web Bean con el primer enlace de interceptor hereda los enlaces de interceptor declarados como meta-anotaciones.

@Transactional @Secure

@InterceptorBindingType
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action { ... }

Cualquier Web Bean anotado @Action estará vinculado a TransactionInterceptor y SecurityInterceptor. (E incluso a TransactionalSecureInterceptor, si éste existe.)

La anotación @Interceptors definida por la especificación de EJB es compatible con Web Beans empresariales y sencillos, por ejemplo:

@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})

public class ShoppingCart {
    public void checkout() { ... }
}

Sin embargo, este enfoque tiene los siguientes inconvenientes:

Por lo tanto, recomendamos el uso de Web Beans estilo interceptor de enlaces.