2009年3月15日 星期日

[Struts2] 深入探討 Interceptor

先前我們已經簡單的介紹了 interceptor 的功能以及整個 interceptor stack 與 Action 呼叫之間的順序!現在我們要將我們的焦點往 interceptor 拉近一些,也就是我們要看看每一個 interceptor 內部的實做面,不過在這裡我們並不會開發我們自己的 interceptor!

Introduce Interceptor 中我們有提到 ActionInvocation 物件,這個物件扮演著整個 interceptor stack 最重要的核心角色!接下來我將會分成兩個 section 來探討我們的主題:1) ActionInvocation guy 與 2) Interceptor 的流程。

ActionInvocation guy

我們之前說過,ActionInvocation 是整個 interceptor stack 中最重要的核心角色,不過當我們瞭解 ActionInvocation 物件時,並不代表我們就會瞭解整個 Struts2 framework 對於處理 request 的流程!當我們在開發 interceptor 時,我們並不會直接的與 ActionInvocation 物件互動,而是間接的與 ActionInvocation 有關係!

ActionInvocation 是一個包裝了所有與 Action 執行有關的 detail information 的物件,當我們的 framework 接收到一個使用者的 request 時,Struts2 framework 會根據使用者呼叫的 URL 來 mapping 所對應的 Action,並且會將此 Action 的相關資訊加入到 ActionInvocation 物件中,接著 Struts2 framework 就會搜尋所有 configuration file 中的所有 interceptors 並且加到 ActionInvocation 中,幫助 ActionInvocation 走訪所有的 interceptors。所以,ActionInvocation 會紀錄整個 request processing 的重要資訊,並且當整個 Struts2 framework 在運作時,ActionInvocation 物件會決定哪一個 component 將會是下一個被呼叫,以及該 component 被呼叫時要給予哪些 data 等等的工作!

Interceptor 的流程

介紹完整個 interceptor stack 中的核心角色後,我們接著就要來看看單一 interceptor 內部執行的流程!當系統中的 ActionInvocation 物件被 setup 完成後,接著就會依照 configuration file 中設定的 interceptor 順序來執行所有的 interceptors。然而在 ActionInvocation 中最重要的 operator 就是 invoke() method,這個 method 會在 ActionInvocation 被 Struts2 framework 設定完成後第一個呼叫的 method,因為 invoke() method 中會具備有執行 interceptor stack 中所有 interceptors 的功能。所以當 invoke() method 第一次被呼叫時,ActionInvocation 就會執行 stack 中第一個 interceptor。值得注意的是,invoke() method 第一的執行並不匯總是執行第一個 interceptor,執行哪一個 interceptor 與傳送哪些資料最終還是由 ActionInvocation 決定,當我們的 interceptor 要被執行時,ActionInvocation 就會呼叫 interceptor 中的 intercept() method

當每一次 invoke() method 被呼叫時,ActionInvocation 會決定接下來是哪一個 interceptor 要被執行,然後呼叫該 interceptor 的 intercept() method。這樣的流程會被執行道沒有下一個 interceptor 要被執行時,ActionInvocation 就會改呼叫 Action 的 execute() method 來執行真正的 business logic,再來 ActionInvocation 就會依照相反地順序呼叫剛剛的 interceptors!

不知道你是否有看出來?這樣的 interceptor stack 的呼叫是一種 recursive 的方是在執行。當前一個 interceptor 呼叫 invoke() method 後,就會執行當前 interceptor 的 preprocessing 程式,接著就要再呼叫 invoke() method,讓 ActionInvocation 執行下一個 interceptor 的 preprocessing,當所有 interceptors 的 proprocessing 完成後才是 Action 的執行,最後在反向的執行每個 interceptor 的 postprocessing。由圖一我們可以看出一個 interceptor 的執行週期。

圖一 Interceptor 的執行週期

讓我們整理一下單一的 interceptor 在撰寫程式時的結構:

  1. 執行 Preprocessing,在這個階段我們可以準備一些在 Action 執行前的作業,我們可以 filter data, alert message 或是處理重要的 data。
  2. 將控制權轉交給下一個 interceptor,而最終是交給 Action 的 execute() method,所以我們呼叫 ActionInvocation.invoke()。在呼叫後,invoke() method 會回傳一個 control string,這個 control string 會由下一個 interceptor 傳遞過來,如果整個執行流程中沒有任何的失誤,control string 將會是我們之前在 Action 的 execute() method 所回傳的那個 string。
  3. 執行 Postprocessing,當我們接收到 control string 後,我們就可以開始執行 postprocessing 的動作,在這裡可以做一些資料的後置處理如:logging 等。不過必須注意的是:當我們獲得 control string 後,代表著回傳給使用者的頁面已經被確定了!所以我們更改 control string 的內容並不會造成頁面的不同!也就是說,當我們需要對 control string 做改變時,我們必須在 preprocessing 階段就動手,這樣才會算數!

在這裡我們比較深入的討論到 interceptor 內部的動作,接下來我們才會著手進行我們自己的 interceptor。

沒有留言: