SeamFramework.orgCommunity Documentation
Web Beans re utiliza a arquitetura básica do interceptor de EJB 3.0, que extende a funcionalidade em duas direções:
Qualquer Web Bean pode ter interceptores, não apenas session beans.
Web Beans possui uma abordagem mais sofisticadas baseada em anotações para associar interceptores aos Web Beans.
A especificação de EJB define dois tipos de pontos de interceptação:
interceptação de métodos de negócios, e
interceptadores de chamadas de ciclo de vida
A business method interceptor applies to invocations of methods of the Web Bean by clients of the Web Bean:
public class TransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
A lifecycle callback interceptor applies to invocations of lifecycle callbacks by the container:
public class DependencyInjectionInterceptor {
@PostConstruct public void injectDependencies(InvocationContext ctx) { ... }
}
An interceptor class may intercept both lifecycle callbacks and business methods.
Suppose we want to declare that some of our Web Beans are transactional. The first thing we need is an interceptor binding annotation to specify exactly which Web Beans we're interested in:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}
Now we can easily specify that our ShoppingCart
is a transactional object:
@Transactional
public class ShoppingCart { ... }
Or, if we prefer, we can specify that just one method is transactional:
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
That's great, but somewhere along the line we're going to have to actually implement the interceptor that provides this transaction management aspect. All we need to do is create a standard EJB interceptor, and annotate it @Interceptor
and @Transactional
.
@Transactional @Interceptor
public class TransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
All Web Beans interceptors are simple Web Beans, and can take advantage of dependency injection and contextual lifecycle management.
@ApplicationScoped @Transactional @Interceptor
public class TransactionInterceptor {
@Resource Transaction transaction;
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
Multiple interceptors may use the same interceptor binding type.
Finalmente, temos que ativar nossos interceptadores no web-beans.xml
.
<Interceptors>
<tx:TransactionInterceptor/>
</Interceptors
>
Whoah! Why the angle bracket stew?
Bem, a declaração XML resolve dois problemas:
o que nos permite especificar totalmente a ordem para todos os interceptores em nosso sistema, garantindo um comportamento determinístico, e
it lets us enable or disable interceptor classes at deployment time.
For example, we could specify that our security interceptor runs before our TransactionInterceptor
.
<Interceptors>
<sx:SecurityInterceptor/>
<tx:TransactionInterceptor/>
</Interceptors
>
Or we could turn them both off in our test environment!
Suponhamos que queremos acrescentar algumas informações adicionais para o nossa anotação @Transactional
:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
boolean requiresNew() default false;
}
Web Beans will use the value of requiresNew
to choose between two different interceptors, TransactionInterceptor
and RequiresNewTransactionInterceptor
.
@Transactional(requiresNew=true) @Interceptor
public class RequiresNewTransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
Now we can use RequiresNewTransactionInterceptor
like this:
@Transactional(requiresNew=true)
public class ShoppingCart { ... }
But what if we only have one interceptor and we want the manager to ignore the value of requiresNew
when binding interceptors? We can use the @NonBinding
annotation:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
@NonBinding String[] rolesAllowed() default {};
}
Usually we use combinations of interceptor bindings types to bind multiple interceptors to a Web Bean. For example, the following declaration would be used to bind TransactionInterceptor
and SecurityInterceptor
to the same Web Bean:
@Secure(rolesAllowed="admin") @Transactional
public class ShoppingCart { ... }
However, in very complex cases, an interceptor itself may specify some combination of interceptor binding types:
@Transactional @Secure @Interceptor
public class TransactionalSecureInterceptor { ... }
Then this interceptor could be bound to the checkout()
method using any one of the following combinations:
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() { ... }
}
One limitation of the Java language support for annotations is the lack of annotation inheritance. Really, annotations should have reuse built in, to allow this kind of thing to work:
public @interface Action extends Transactional, Secure { ... }
Well, fortunately, Web Beans works around this missing feature of Java. We may annotate one interceptor binding type with other interceptor binding types. The interceptor bindings are transitive any Web Bean with the first interceptor binding inherits the interceptor bindings declared as meta-annotations.
@Transactional @Secure
@InterceptorBindingType
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action { ... }
Any Web Bean annotated @Action
will be bound to both TransactionInterceptor
and SecurityInterceptor
. (And even TransactionalSecureInterceptor
, if it exists.)
The @Interceptors
annotation defined by the EJB specification is supported for both enterprise and simple Web Beans, for example:
@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})
public class ShoppingCart {
public void checkout() { ... }
}
However, this approach suffers the following drawbacks:
the interceptor implementation is hardcoded in business code,
interceptors may not be easily disabled at deployment time, and
the interceptor ordering is non-global it is determined by the order in which interceptors are listed at the class level.
Therefore, we recommend the use of Web Beans-style interceptor bindings.