攔截器的功能是定義在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() { ... } }
但缺點也很明顯,不推薦使用.缺點以下: