SeamFramework.orgCommunity Documentation
Web Beans重用了EJB3.0的基本的拦截器体系,并且在两个方向上扩展了其功能:
任何Web Bean都可以拥有拦截器,而不仅仅是会话Bean。
Web Beans拥有一个更复杂的基于注释的方法将拦截器绑定到Web Bean上。
EJB规范定义了两种拦截点:
业务方法拦截,和
生命周期回调方法拦截。
一个 业务方法拦截 是Web Bean的客户应用在Web Bean的方法调用上:
public class TransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
一个 生命周期回调拦截器 是容器应用在生命周期回调方法的调用上:
public class DependencyInjectionInterceptor {
@PostConstruct public void injectDependencies(InvocationContext ctx) { ... }
}
一个拦截器类既可以拦截生命周期回调方法,也可以拦截业务方法。
假定我们想声明我们的某些Web Beans是事务性的。我们要做的第一个事情就是需要一个 拦截器绑定注释 以便指定哪些Web Beans是事务性的:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}
现在我们可以很容易地指定我们的 ShoppingCart
是一个事务性的对象:
@Transactional
public class ShoppingCart { ... }
或者,如果我们愿意的话,我们可以仅仅指定一个方法是事务性的:
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
很好,但是在代码中有些地方需要我们实现提供事务管理的拦截器。我们需要做的事情就是创建一个标准的EJB拦截器,使用 @Interceptor
和 @Transactional
注释它。
@Transactional @Interceptor
public class TransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
所有的Web Beans拦截器都是简单的Web Beans,因此可以使用依赖注入和具有上下文的生命周期的管理。
@ApplicationScoped @Transactional @Interceptor
public class TransactionInterceptor {
@Resource Transaction transaction;
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
多个拦截器可以使用相同的拦截器绑定类型
最后,我们需要在 web-beans.xml
配置文件中 激活 我们的拦截器。
<Interceptors>
<tx:TransactionInterceptor/>
</Interceptors
>
哇塞!为何使用尖括号?
好吧,XML声明解决了两个问题:
它可以让我们在我们的系统中指定所有的拦截器顺序,确保这些行为具有确定性,并且
它能够让我们在部署期间激活或者关闭拦截器类。
例如,我们可以指定在 TransactionInterceptor
之前运行我们的安全拦截器。
<Interceptors>
<sx:SecurityInterceptor/>
<tx:TransactionInterceptor/>
</Interceptors
>
或者我们可以在测试环境中将它们都关闭!
假定我们想要往 @Transactional
注释中添加一些额外信息:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
boolean requiresNew() default false;
}
Web Beans将使用 requiresNew
的值来决定在两种不同的拦截器 TransactionInterceptor
和 RequiresNewTransactionInterceptor
中选择哪一个。
@Transactional(requiresNew=true) @Interceptor
public class RequiresNewTransactionInterceptor {
@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}
现在我们可以像这样使用 RequiresNewTransactionInterceptor
:
@Transactional(requiresNew=true)
public class ShoppingCart { ... }
但是如果我们只有一个拦截器,并且我们希望管理器在绑定拦截器的时候忽略 requiresNew
的值,那该怎么办?我们可以使用 @NonBinding
注释:
@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
@NonBinding String[] rolesAllowed() default {};
}
通常我们可以组合拦截器绑定类型将多个拦截器绑定到一个Web Bean上。例如,下面的声明可以将 TransactionInterceptor
和 SecurityInterceptor
绑定到相同的Web Bean上:
@Secure(rolesAllowed="admin") @Transactional
public class ShoppingCart { ... }
然而,在非常复杂的情况下,一个拦截器本身可以指定一些拦截器绑定类型的组合:
@Transactional @Secure @Interceptor
public class TransactionalSecureInterceptor { ... }
然后,这个拦截器可以使用下面的任何一个组合来绑定到 checkout()
方法上:
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() { ... }
}
Java语言对注释的支持有一个限制,那就是缺少注释的继承机制。实际上,注释应该可以重用内置,应该支持下列工作:
public @interface Action extends Transactional, Secure { ... }
不过幸运的是,Web Beans能够解决这个Java缺失的特性。我们可以向一个拦截器绑定类型注释另一个拦截器绑定类型。拦截器绑定是具有传递性的 拥有第一个拦截器绑定的任何Web Bean都继承被声明为元注释的拦截器绑定。
@Transactional @Secure
@InterceptorBindingType
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action { ... }
任何使用 @Action
注释的Web Bean都被绑定到 TransactionInterceptor
和 SecurityInterceptor
。(如果存在 TransactionalSecureInterceptor
的话,甚至可以绑定到这个拦截器)
企业级和简单的Web Bean都支持EJB规范指定的 @Interceptors
注释,例如:
@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})
public class ShoppingCart {
public void checkout() { ... }
}
然而,这种方法具有下列缺陷:
拦截器实现被硬编码到在业务代码中,
拦截器可能无法轻松地在部署期间关闭,并且
拦截器的顺序是非全局性的 它由在类级别上列出的拦截器的顺序决定。
因此,我们建议使用Web Bean风格的拦截器绑定。