7.11. Seam interceptors
EJB3 introduced a standard interceptor model for session bean components. To add an interceptor to a bean, you need to write a class with a method annotated
@AroundInvoke
and annotate the bean with an @Interceptors
annotation that specifies the name of the interceptor class. For example, the following interceptor checks that the user is logged in before allowing invoking an action listener method:
public class LoggedInInterceptor { @AroundInvoke public Object checkLoggedIn(InvocationContext invocation) throws Exception { boolean isLoggedIn = Contexts.getSessionContext() .get("loggedIn")!=null; if (isLoggedIn) { //the user is already logged in return invocation.proceed(); } else { //the user is not logged in, fwd to login page return "login"; } } }
To apply this interceptor to a session bean acting as an action listener, we must annotate the session bean
@Interceptors(LoggedInInterceptor.class)
. However, Seam builds upon the interceptor framework in EJB3 by allowing you to use @Interceptors
as a meta-annotation for class level interceptors (those annotated @Target(TYPE)
). In this example, we would create an @LoggedIn
annotation, as follows:
@Target(TYPE) @Retention(RUNTIME) @Interceptors(LoggedInInterceptor.class) public @interface LoggedIn {}
We can now annotate our action listener bean with
@LoggedIn
to apply the interceptor.
@Stateless @Name("changePasswordAction") @LoggedIn @Interceptors(SeamInterceptor.class) public class ChangePasswordAction implements ChangePassword { ... public String changePassword() { ... } }
Where interceptor order is important, add
@Interceptor
annotations to your interceptor classes to specify a particular order of interceptors.
@Interceptor(around={BijectionInterceptor.class, ValidationInterceptor.class, ConversationInterceptor.class}, within=RemoveInterceptor.class) public class LoggedInInterceptor { ... }
You can even have a client-side interceptor, for built-in EJB3 functions:
@Interceptor(type=CLIENT) public class LoggedInInterceptor { ... }
EJB interceptors are stateful, and their life cycles match that of the component they intercept. For interceptors that do not need to maintain state, Seam allows performance optimization where
@Interceptor(stateless=true)
is specified.
Much of Seam's functionality is implemented as a set of built-in Seam interceptors, including the interceptors named in the previous example. These interceptors exist for all interceptable Seam components; you need not specify them explicitly through annotation.
Seam interceptors can also be used with JavaBean components.
EJB defines interception not only for business methods (using
@AroundInvoke
), but also for the life cycle methods @PostConstruct
, @PreDestroy
, @PrePassivate
and @PostActive
. Seam supports these life cycle methods on both component and interceptor, not only for EJB3 beans, but also for JavaBean components (except @PreDestroy
, which is not meaningful for JavaBean components).