設計模式之管道和過濾器的應用

 

軟件設計的一個核心問題是能否使用重複的體系架構,即能否達到體系架構級的軟件重用。也就是說,能否在不同的軟件系統中,使用同一體系架構。基於這個目的,許多學者們開始研究和實踐軟件體系架構的模式問題。在<Pattern-Oriented Software Architecture (面向模式的軟件體系架構) >中首次提出了8種體系結構模式:

層(L a y e r s)、管道和過濾器(Pipes and Filters) 、黑板( B l a c k b o a r d )、代理者( B r o k e r)、模型-視圖-控制器( M o d e l - Vi e w - C o n t r o l l e r)、表示-抽象-控制(P r e s e n t a t i o n - A b s t r a c t i o n - C o n t r o l)、微核(M i c r o k e r n e l)、映像(R e f l e c t i o n)。

 

管道和過濾器(Pipes and Filters)體系架構模式是爲處理數據流的系統提供的一種模式。它是由過濾器和管道組成的.每個處理步驟都被封裝在一個過濾器組件中,數據通過相鄰過濾器之間的管道進行傳輸。每個過濾器可以單獨修改,功能單一,並且它們之間的順序可以進行配置。下圖是管道/過濾器模式的示意圖。一個典型的管道/過濾器體系結構的例子是以Unix shell編寫的程序。Unix既提供一種符號,以連接各組成部分(Unix的進程),又提供某種進程運行時機制以實現管道。另一個著名的例子是傳統的編譯器。傳統的編譯器一直被認爲是一種管道系統,在該系統中,一個階段(包括詞法分析、語法分析、語義分析和代碼生成)的輸出是另一個階段的輸入。

 

 

 

4 Servlet2.3 Filter


4.1 Servlet Filter概述


凡是開發過J2EE的web application的人員都知道,經常需要處理以下幾種情況:



  • 訪問特定資源(Web 頁、JSP 頁、servlet)時的身份認證
  • 應用程序級的訪問資源的審覈和記錄
  • 應用程序範圍內對資源的加密訪問,它建立在定製的加密方案基礎上
  • 對被訪問資源的及時轉換, 包括從 servlet 和 JSP 的動態輸出

在servlet2.3之前這些功能處理是很難實現的,但是Java Servlet 2.3 規範新增了不少激動人心的功能,其中之一便是過濾器(Filter),其實這就是我們所說的管道和過濾器體系架構在J2EE中的應用實踐. 通過使用該模式使得Web Application開發者能夠在請求到達Web資源之前截取請求,在處理請求之後修改應答。其結構圖如下:





 


一個執行過濾器的Java 類必須實現javax.servlet.Filter 接口。這一接口含有三個方法:



  • init(FilterConfig):這是容器所調用的初始化方法。它保證了在第一次 doFilter() 調用前由容器調用。它能獲取在 web.xml 文件中指定的filter初始化參數。
  • doFilter(ServletRequest, ServletResponse, FilterChain):這是一個完成過濾行爲的方法。它同樣是上一個過濾器調用的方法。引入的 FilterChain 對象提供了後續過濾器所要調用的信息。
  • destroy():容器在銷燬過濾器實例前,doFilter()中的所有活動都被該實例終止後,調用該方法。




 


4.2 Filter鏈介紹


所有過濾器都服從調用的過濾器鏈,並通過定義明確的接口得到執行。WebApplication可以指定許多過濾器來完成相關的工作.那麼它們就組成一個過濾器鏈來完成相應的工作.其結構如下圖:





 


4.3 例子


4.3.1 簡單filter


在PetStore1.3.1中的就存在兩個Filter過濾器.其中一個過濾器,完成字符集的編碼的轉化,如大家經常遇到的漢字編碼問題,你只需配置爲GBK即可.它從Web.xml之中讀取這些參數的配置信息,然後進行編碼的轉化.另一個是安全校驗Fliter,它負責進行安全檢查哪些頁面可以進行,哪些不可.它們組成一個Filter鏈,結構圖和實現代碼如下(完整代碼參見附件):





 



容器通過 Web 應用程序中的配置描述符 web.xml 文件解析過濾器配置信息。有兩個新的標記與過濾器相關:<filter> 和 <filter-mapping>。<filter> 標記是一個過濾器定義,它必定有一個 <filter- name> 和 <filter-class> 子元素。<filter-name> 子元素給出了一個與過濾器實例相關的名字。<filter-class> 指定了由容器載入的實現類。您能隨意地包含一個 <init-param> 子元素爲過濾器實例提供初始化參數。<filter-mapping> 標記代表了一個過濾器的映射,指定了過濾器會對其產生作用的 URL 的子集。



4.3.2 複雜的filter


上面是petstore的例子,演示了通過Fliter修改字符編碼和安全認證的功能.下面提供一個示例演示通過修改返回數據(通過過濾器把response的字符串變成大寫).



該示例使用HttpServletResponseWrapper技術,它是對HttpServletResponse的包裝,其實就是裝飾(decorate)設計模式的應用.這個例子能夠工作的關鍵是UCaseResponse和UCaseWriter類,它實現了對每個要輸出的字符都轉成了大寫後再寫入實際的輸出流的功能。


4.4 體系架構的實現


實現一個管道和過濾器一般要注意以下幾個方面:



  • 把系統任務分成一系列處理階段。
    根據管道和過濾器的設計方案,必須把系統處理的任務分割成相應獨立的任務,如日誌,數據轉化,安全認證等.這樣每個階段僅依賴其前一階段的輸出。通過數據流將所有階段相連起來。並且你可以進行替換每個步驟,或者可以調整它們之間的順序,以產生新的結果.
    如petstore中的編碼轉化Filter和安全Filter,分成兩個獨立的處理階段.

  • 定義沿每個管道傳輸的數據格式。
    我們知道每個過濾器,定義一個統一格式以獲得最大的靈活性,因爲它使過濾器的重組變得容易。如:每個過濾器的方法是doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)它們的參數是必須相同的.

  • 決定如何實現每個管道連接
    Filter過濾器的連接是推得方式來實現的.前一個過濾器主動的調用filterChain.doFilter(request, response);來實現轉向下一個過濾器.

  • 設計和實現過濾器
    設計每個Filter具有獨立的功能,如編碼轉化,安全校驗,等功能.並且每個Fliter都應該在實現javax.servlet.Filter接口.

  • 建立處理流水線
    過濾器的部署是在Web.xml中進行配置,描述過濾器的實現類以及它們的map關係,來確定它們的順序.

 

在使用管道和過濾器模式時,一般會使用以下的GOF設計模式.


 

6.1 職責鏈模式(Chain Of Responsibility)


 

職責鏈設計模式的意圖就是使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。其實管道和過濾器模式就是職責鏈模式的抽象,把它應用到軟件體系架構中.


 

6.2 命令模式(Command)


 

命令模式的意圖將一個請求封裝爲一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤消的操作。在管道和過濾器模式中每個過濾器一般使用命令模式,把請求封裝成一個命令進行處理.


 

6.3 裝飾模式(Decorator)


 

裝飾模式的意圖就是動態地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更爲靈活。


 

在管道和過濾器模式中,在每個過濾器中經常需要對請求進行動態的增加功能,或者修改請求的內容,這時一般會使用裝飾模式.如Servlet filter的javax.servlet.http.HttpServletRequestWrapper, javax.servlet.http.HttpServletResponseWrapper就是裝飾模式的應用.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章