1. 程式人生 > >AOP(面向切面程式設計)、Filter(過慮器)、Interceptor(攔截器)

AOP(面向切面程式設計)、Filter(過慮器)、Interceptor(攔截器)

AOP(面向切面程式設計)

      面向切面程式設計(AOP是Aspect Oriented Program的首字母縮寫) ,我們知道,面向物件的特點是繼承、多型和封裝。而封裝就要求將功能分散到不同的物件中去,這在軟體設計中往往稱為職責分配。實際上也就是說,讓不同的類設計不同的方法。這樣程式碼就分散到一個個的類中去了。這樣做的好處是降低了程式碼的複雜程度,使類可重用。

      但是人們也發現,在分散程式碼的同時,也增加了程式碼的重複性。什麼意思呢?比如說,我們在兩個類中,可能都需要在每個方法中做日誌。按面向物件的設計方法,我們就必須在兩個類的方法中都加入日誌的內容。也許他們是完全相同的,但就是因為面向物件的設計讓類與類之間無法聯絡,而不能將這些重複的程式碼統一起來。

    也許有人會說,那好辦啊,我們可以將這段程式碼寫在一個獨立的類獨立的方法裡,然後再在這兩個類中呼叫。但是,這樣一來,這兩個類跟我們上面提到的獨立的類就有耦合了,它的改變會影響這兩個類。那麼,有沒有什麼辦法,能讓我們在需要的時候,隨意地加入程式碼呢?這種在執行時,動態地將程式碼切入到類的指定方法、指定位置上的程式設計思想就是面向切面的程式設計。

       一般而言,我們管切入到指定類指定方法的程式碼片段稱為切面,而切入到哪些類、哪些方法則叫切入點。有了AOP,我們就可以把幾個類共有的程式碼,抽取到一個切片中,等到需要時再切入物件中去,從而改變其原有的行為。這樣看來,AOP其實只是OOP的補充而已。OOP從橫向上區分出一個個的類來,而AOP則從縱向上向物件中加入特定的程式碼。有了AOP,OOP變得立體了。如果加上時間維度,AOP使OOP由原來的二維變為三維了,由平面變成立體了。從技術上來說,AOP基本上是通過代理機制實現的。      AOP在程式設計歷史上可以說是里程碑式的,對OOP程式設計是一種十分有益的補充。

       AOP不一定都像Spring AOP那樣,是在執行時生成代理物件來織入的,還可以在編譯期、類載入期織入,比如AspectJ。AOP像OOP一樣,只是一種程式設計正規化,AOP並沒有規定說,實現AOP協議的程式碼,要用什麼方式去實現。

什麼是代理模式,就是我再生成一個代理類,去代理UserController的saveUser()方法,程式碼大概就長這樣:

class UserControllerProxy {
    private UserController userController;

    public void saveUser() {
        checkAuth();
        userController.saveUser();
    }
}
       代理分為靜態代理和動態代理,靜態代理,顧名思義,就是你自己寫代理物件,動態代理,則是在執行期,生成一個代理物件。Spring AOP就是基於動態代理的,但是不是所有AOP的實現都是在執行時進行織入的,因為這樣效率太低了,而且只能針對方法進行AOP,無法針對建構函式、欄位進行AOP。我完全可以在編譯成class時就織入啊,比如AspectJ,當然AspectJ還提供了後編譯器織入和類載入期織入。

AOP概念

  — 方面(Aspect):一個關注點的模組化,這個關注點實現可能另外橫切多個物件。事務管理是J2EE應用中一個很好的橫切關注點例子。方面用Spring的Advisor或攔截器實現。

  — 連線點(Joinpoint):程式執行過程中明確的點,如方法的呼叫或特定的異常被丟擲。

  — 通知(Advice):在特定的連線點,AOP框架執行的動作。各種型別的通知包括“around”、“before”和“throws”通知。通知型別將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護一個“圍繞”連線點的攔截器鏈。

  — 切入點(Pointcut):指定一個通知將被引發的一系列連線點的集合。AOP框架必須允許開發者指定切入點,例如,使用正則表示式。

  — 引入(Introduction):新增方法或欄位到被通知的類。Spring允許引入新的介面到任何被通知的物件。例如,你可以使用一個引入使任何物件實現IsModified介面,來簡化快取。

  — 目標物件(Target Object):包含連線點的物件,也被稱作被通知或被代理物件。

  — AOP代理(AOP Proxy):AOP框架建立的物件,包含通知。在Spring中,AOP代理可以是JDK動態代理或CGLIB代理。

  — 編織(Weaving):組裝方面來建立一個被通知物件。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在執行時完成。Spring和其他純Java AOP框架一樣,在執行時完成織入。

  各種通知型別包括:

  —  Around通知:包圍一個連線點的通知,如方法呼叫。這是最強大的通知。Aroud通知在方法呼叫前後完成自定義的行為,它們負責選擇繼續執行連線點或通過返回它們自己的返回值或丟擲異常來短路執行。

  —  Before通知:在一個連線點之前執行的通知,但這個通知不能阻止連線點前的執行(除非它丟擲一個異常)。

  —  Throws通知:在方法丟擲異常時執行的通知。Spring提供強制型別的Throws通知,因此你可以書寫程式碼捕獲感興趣的異常(和它的子類),不需要從Throwable或Exception強制型別轉換。

  —  After returning通知:在連線點正常完成後執行的通知,例如,一個方法正常返回,沒有丟擲異常。

  Around通知是最通用的通知型別。大部分基於攔截的AOP框架(如Nanning和Jboss 4)只提供Around通知。

  如同AspectJ,Spring提供所有型別的通知,我們推薦你使用最為合適的通知型別來實現需要的行為。例如,如果只是需要用一個方法的返回值來更新快取,你最好實現一個after returning通知,而不是around通知,雖然around通知也能完成同樣的事情。使用最合適的通知型別使程式設計模型變得簡單,並能減少潛在錯誤。例如,你不需要呼叫在around通知中所需使用的MethodInvocation的proceed()方法,因此就呼叫失敗。

  切入點的概念是AOP的關鍵,它使AOP區別於其他使用攔截的技術。切入點使通知獨立於OO的層次選定目標。例如,提供宣告式事務管理的around通知可以被應用到跨越多個物件的一組方法上。 因此切入點構成了AOP的結構要素。


Filter(過慮器)

Filter技術是Servlet2.3新增加的功能,Servlet2.3是sun公司於2000年10月釋出的,它的開發者包括許多個人和公司團體,充分體現了sun公司所倡導的程式碼開放性原則。在眾多參與者的共同努力下,Servlet2.3比以往功能都強大了很多,而且效能也有了提高。那麼Filter有什麼功能呢?Filter可以用來設定字符集、控制權限、控制轉向等等。簡單點說:就是定義在訪問某物件之前和訪問之後要做的事情。

Interceptor(攔截器)

1,攔截器的概念
    java裡的攔截器是動態攔截Action呼叫的物件,它提供了一種機制可以使開發者在一個Action執行的前後執行一段程式碼,也可以在一個Action
執行前阻止其執行,同時也提供了一種可以提取Action中可重用部分程式碼的方式。在AOP中,攔截器用於在某個方法或者欄位被訪問之前,進行攔截
然後再之前或者之後加入某些操作。目前,我們需要掌握的主要是Spring的攔截器,Struts2的攔截器不用深究,知道即可。

2,攔截器的原理
    大部分時候,攔截器方法都是通過代理的方式來呼叫的。Struts2的攔截器實現相對簡單。當請求到達Struts2的ServletDispatcher時,Struts2
會查詢配置檔案,並根據配置例項化相對的攔截器物件,然後串成一個列表(List),最後一個一個的呼叫列表中的攔截器。Struts2的攔截器是可
插拔的,攔截器是AOP的一個實現。Struts2攔截器棧就是將攔截器按一定的順序連線成一條鏈。在訪問被攔截的方法或者欄位時,Struts2攔截器鏈
中的攔截器就會按照之前定義的順序進行呼叫。

3,自定義攔截器的步驟
    第一步:自定義一個實現了Interceptor介面的類,或者繼承抽象類AbstractInterceptor。
    第二步:在配置檔案中註冊定義的攔截器。
    第三步:在需要使用Action中引用上述定義的攔截器,為了方便也可以將攔截器定義為預設的攔截器,這樣在不加特殊說明的情況下,所有的
Action都被這個攔截器攔截。

4,過濾器與攔截器的區別
    過濾器可以簡單的理解為“取你所想取”,過濾器關注的是web請求;攔截器可以簡單的理解為“拒你所想拒”,攔截器關注的是方法呼叫,比如攔截
敏感詞彙。
4.1,攔截器是基於java反射機制來實現的,而過濾器是基於函式回撥來實現的。(有人說,攔截器是基於動態代理來實現的)
4.2,攔截器不依賴servlet容器,過濾器依賴於servlet容器。
4.3,攔截器只對Action起作用,過濾器可以對所有請求起作用。
4.4,攔截器可以訪問Action上下文和值棧中的物件,過濾器不能。
4.5,在Action的生命週期中,攔截器可以多次呼叫,而過濾器只能在容器初始化時呼叫一次。

5,Spring攔截器
5.1,抽象類HandlerInterceptorAdapter
    我們如果在專案中使用了Spring框架,那麼,我們可以直接繼承HandlerInterceptorAdapter.java這個抽象類,來實現我們自己的攔截器。

Spring框架,對java的攔截器概念進行了包裝,這一點和Struts2很類似。HandlerInterceptorAdapter繼承了抽象介面HandlerInterceptor。

相關參考: