拦截器的功能是定义在Java拦截器规范。 java
拦截器规范定义了三种拦截点:public class DependencyInjectionInterceptor { @PostConstruct public void injectDependencies(InvocationContext ctx) { ... } }EJB超时时使用的拦截器
public class TimeoutInterceptor { @AroundTimeout public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }在业务上,对某一个Bean的方法进行拦截
public class TransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }@AroundInvoke注释指定了要用做拦截器的方法,拦截器方法与被拦截的业务方法执行同一个java调用堆栈、同一个事务和安全上下文中。用@AroundInvoke注释指定的方法必须遵照如下格式:public Object XXX(javax.interceptor.InvocationContext ctx) throws Exception
package javax.interceptor; public interface InvocationContext{ public Object getTarget(); public Method getMethod(); public Ojbect[] getParameters(); public void setParameters(Object[] newArgs); public java.util.Map<String, Ojbect> getContextData(); public Object proceed() throws Exception; }
//被拦截的方法 @Interceptors(HelloInterceptor.class) public class HelloChinaBean { public String SayHello(String name) { return name +"Hello World."; } }
//拦截器定义 public class HelloInterceptor { @AroundInvoke public Object log(InvocationContext ctx) throws Exception { try{ if (ctx.getMethod().getName().equals("SayHello")){ System.out.println("Holle World!!!" ); } return ctx.proceed(); }catch (Exception e) { throw e; } } }
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Transactional {}如今咱们能够很容易地指定类ShoppingCart是事务性对象:
@Transactional public class ShoppingCart { ... }或者咱们能够指定一个方法的事务
public class ShoppingCart { @Transactional public void checkout() { ... } }
@Transactional @Interceptor public class TransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }拦截器能够利用依赖注入:
@Transactional @Interceptor public class TransactionInterceptor { @Resource UserTransaction transaction; @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
多个拦截器可使用相同的拦截器绑定类型。 安全
@Resource和@Inject的区别: app
Injection Mechanism |
Can Inject JNDI Resources Directly |
Can Inject Regular Classes Directly |
Resolves By |
Typesafe |
Resource Injection |
Yes |
No |
Resource name |
No |
Dependency Injection |
No |
Yes |
Type |
Yes |
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"> <interceptors> <class>org.mycompany.myapp.TransactionInterceptor</class> </interceptors> </beans>
这样有2个好处: ui
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"> <interceptors> <class>org.mycompany.myapp.SecurityInterceptor</class> <class>org.mycompany.myapp.TransactionInterceptor</class> </interceptors> </beans>
拦截器毕竟比较重要,不推荐使用@Priority启用.
在CDI中,XML配置的优先级高于@Priority.
关于@Priority能够参考下列: this
public static class Interceptor.Priority
extends Object
Priorities that define the order in which interceptors are invoked. These values should be used with the Priority annotation.
Interceptors defined by platform specifications should have priority values in the range PLATFORM_BEFORE up until LIBRARY_BEFORE, or starting at PLATFORM_AFTER.
Interceptors defined by extension libraries should have priority values in the range LIBRARY_BEFORE up until APPLICATION, or LIBRARY_AFTER up until PLATFORM_AFTER.
Interceptors defined by applications should have priority values in the range APPLICATION up until LIBRARY_AFTER.
An interceptor that must be invoked before or after another defined interceptor can choose any appropriate value.
Interceptors with smaller priority values are called first. If more than one interceptor has the same priority, the relative order of these interceptor is undefined.
For example, an extension library might define an interceptor like this: 编码
@Priority(Interceptor.Priority.LIBRARY_BEFORE+10) @Interceptor public class ValidationInterceptor { ... }
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Transactional { boolean requiresNew() default false; }CDI将使用requiresNew的值选择两个不一样的拦截器,TransactionInterceptor和RequiresNewTransactionInterceptor
@Transactional(requiresNew = true) @Interceptor public class RequiresNewTransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }以下使用:
@Transactional(requiresNew = true) public class ShoppingCart { ... }可是若是咱们只有一个拦截器,咱们但愿容器拦截器绑定时忽略requiresNew的值,也许这些信息只用于拦截器实现。咱们可使用@Nonbinding注释:
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Secure { @Nonbinding String[] rolesAllowed() default {}; }
一般咱们使用拦截器绑定的组合类型绑定多个拦截器bean。例如,下面的声明将用于绑定TransactionInterceptor和SecurityInterceptor这2个拦截器到ShoppingCart. spa
@Secure(rolesAllowed="admin") @Transactional public class ShoppingCart { ... }
然而,在很是复杂的状况下,一个拦截器自己可能指定拦截器绑定类型: code
@Transactional @Secure @Interceptor public class TransactionalSecureInterceptor { ... }
那么这个拦截器能够绑定到checkout() 方法,如下任何组合均可使用: orm
public class ShoppingCart { @Transactional @Secure public void checkout() { ... } }
@Secure public class ShoppingCart { @Transactional public void checkout() { ... } }
@Transactional public class ShoppingCart { @Secure public void checkout() { ... } }
@Transactional @Secure public class ShoppingCart { public void checkout() { ... } }
Java语言支持注解的一个限制就是缺少注解继承.注解应该重用内置已有的.就如同下面这段代码表达的意思 xml
//实际没这写法 public @interface Action extends Transactional, Secure { ... }幸运的是,CDI围绕Java没有的这个特性开展了一些工做.
@Transactional @Secure @InterceptorBinding @Target(TYPE) @Retention(RUNTIME) public @interface Action { ... }如今任何Bean绑定 Action这个注解 ,其实就是绑定到了@Transactional @Secure.(就是拦截器TransactionInterceptor和拦截器SecurityInterceptor). (甚至TransactionalSecureInterceptor,若是它存在.)
这个注解@Interceptors是拦截器规范定义的,cdi是支持的<使用托管bean和EJB规范>.以下:
@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class}) public class ShoppingCart { public void checkout() { ... } }
但缺点也很明显,不推荐使用.缺点以下: