工作总结4:拦截器的使用
1.攔截器綜述
攔截器的功能是定義在Java攔截器規(guī)范。
攔截器規(guī)范定義了三種攔截點:
業(yè)務方法攔截,
生命周期回調(diào)偵聽,
超時攔截(EJB)方法。
在容器的生命周期中進行攔截
EJB超時時使用的攔截器
public class TimeoutInterceptor {@AroundTimeoutpublic Object manageTransaction(InvocationContext ctx) throws Exception { ... } }在業(yè)務上,對某一個Bean的方法進行攔截
public class TransactionInterceptor {@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... } }@AroundInvoke注釋指定了要用作攔截器的方法,攔截器方法與被攔截的業(yè)務方法執(zhí)行同一個java調(diào)用堆棧、同一個事務和安全上下文中。用@AroundInvoke注釋指定的方法必須遵守以下格式:public Object XXX(javax.interceptor.InvocationContext ctx) throws Exception
下面是javax.interceptor.InvocationContext封裝了客戶端所調(diào)用業(yè)務方法的一些信息。
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; }getTarget() 指向被調(diào)用的bean實例
getMethod() 指向被攔截的業(yè)務方法
getParameters() 獲取被攔截業(yè)務方法的參數(shù)
setParameters() 設置被攔截業(yè)務方法的參數(shù)
getContextData() 返回一個Map對象,它在整個方法調(diào)用期間都可以被訪問到。位于同一個方法調(diào)用內(nèi)的不同攔截器之間可以利用它來傳遞上下文相關的數(shù)據(jù)。
示例:
2.攔截器綁定(Interceptor bindings)
假設我們想要申明一些bean的事務。我們先要的是一個攔截器綁定類型來指定哪些bean我們要申明.
首先定義一個注解
@Transactional public class ShoppingCart { ... } 或者我們可以指定一個方法的事務
public class ShoppingCart {@Transactional public void checkout() { ... } }- 1
- 2
- 3
2.攔截器實現(xiàn)(Implementing interceptors)
我們實際上要實現(xiàn)提供了這種事務管理方面的攔截器,所以我們需要做的是創(chuàng)建一個標準的攔截,并配上@Interceptor和@transactional注解.
@Transactional @Interceptor public class TransactionInterceptor {@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... } }攔截器可以利用依賴注入:
@Transactional @Interceptor public class TransactionInterceptor {@Resource UserTransaction transaction;@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... } }多個攔截器可以使用相同的攔截器綁定類型。
@Resource和@Inject的區(qū)別:
3.啟用攔截器(Enabling interceptors)
默認情況下,所有攔截器被禁用.要使用攔截器.需要在bean.xml中進行配置,以啟用.從CDI 1.1起攔截器可以使用@Priority注釋為整個應用程序啟用。
<beansxmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"><interceptors><class>org.mycompany.myapp.TransactionInterceptor</class></interceptors> </beans>這樣有2個好處:
攔截器比較重要,在XML中確保其確定性行為
它讓我們在部署時啟用或禁用攔截器類。
當然也可以配置啟用多個攔截器
攔截器畢竟比較重要,不推薦使用@Priority啟用.
在CDI中,XML配置的優(yōu)先級高于@Priority.
關于@Priority可以參考下列:
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)@Interceptorpublic class ValidationInterceptor { ... }4.Interceptor bindings with members(攔截器注解屬性)
假設我們想要添加一些額外的信息給我們的@transactional注解:
CDI將使用requiresNew的值選擇兩個不同的攔截器,TransactionInterceptor和RequiresNewTransactionInterceptor
下面是requiresNew為true的攔截器
@Transactional(requiresNew = true) @Interceptor public class RequiresNewTransactionInterceptor {@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... } }如下使用:
@Transactional(requiresNew = true) public class ShoppingCart { ... }但是如果我們只有一個攔截器,我們希望容器攔截器綁定時忽略requiresNew的值,也許這些信息只用于攔截器實現(xiàn)。我們可以使用@Nonbinding注釋:
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Secure {@Nonbinding String[] rolesAllowed() default {}; }5.Multiple interceptor binding annotations(多重攔截器綁定注解)
通常我們使用攔截器綁定的組合類型綁定多個攔截器bean。例如,下面的聲明將用于綁定TransactionInterceptor和SecurityInterceptor這2個攔截器到ShoppingCart.
@Secure(rolesAllowed="admin") @Transactional public class ShoppingCart { ... }然而,在非常復雜的情況下,一個攔截器本身可能指定攔截器綁定類型:
@Transactional @Secure @Interceptor public class TransactionalSecureInterceptor { ... }- 1
- 2
那么這個攔截器可以綁定到checkout() 方法,以下任何組合都可使用:
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() { ... } }6. Interceptor binding type inheritance(攔截器綁定類型繼承)
Java語言支持注解的一個限制就是缺乏注解繼承.注解應該重用內(nèi)置已有的.就如同下面這段代碼表達的意思
//實際沒這寫法 public @interface Action extends Transactional, Secure { ... }- 1
- 2
幸運的是,CDI圍繞Java沒有的這個特性開展了一些工作.
我們會標注一個攔截器綁定類型,其有其他攔截器的綁定類型,(稱為元注解)
表述起來有點費勁,就如同下面代碼這樣.
現(xiàn)在任何Bean綁定 Action這個注解 ,其實就是綁定到了@Transactional @Secure.(就是攔截器TransactionInterceptor和攔截器SecurityInterceptor). (甚至TransactionalSecureInterceptor,如果它存在.)
7.Use of @Interceptors(同時用多個攔截器)
這個注解@Interceptors是攔截器規(guī)范定義的,cdi是支持的<使用托管bean和EJB規(guī)范>.如下:
但缺點也很明顯,不推薦使用.缺點如下:
攔截器在代碼中是硬編碼.
攔截器在部署時不好更改.
攔截器命令是非全局的——它是在類級別由攔截器的順序列出.
因此還是使用上面CDI的使用方式比較好.
總結
以上是生活随笔為你收集整理的工作总结4:拦截器的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(2421):项目反馈
- 下一篇: 2018百度之星程序设计大赛初赛B——1