多视角透析Struts2
3.3 多視角透析Struts2?
Struts2的外部環境并不復雜,因為其核心內容非常明確:探究Struts2運行時所必須的基本要素。我們對Struts2的運行環境和Struts2所依賴的核心技術的講解,更多是為了讓讀者了解Struts2能夠順利運行的條件。?
在明確了Struts2的外部環境之后,我們討論的話題就將轉向Struts2本身。在本節中,我們將從宏觀和微觀這兩個不同的視角,闡述Struts2的總體架構和內部元素構成,以此揭開Struts2的神秘面紗。?
3.3.1透視鏡 —— Struts2的宏觀視圖?
Struts2的宏觀視圖是指站在整個框架的角度,程序的運行可以劃分為哪些邏輯運行主線。對于一個框架的邏輯運行主線的研究,也是我們分析一個框架最為重要的切入點。而這一切入點,就位于Struts2的核心入口程序之中。?
3.3.1.1 Struts2的核心入口程序?
Struts2的核心入口程序,從功能上講必須能夠處理Http請求,這是表示層框架的基本要求。為了達到這一要求,Struts2毫無例外地遵循了Servlet標準,通過實現標準的Filter接口來進行Http請求的處理。我們通過在web.xml中指定這個實現類,就可以將Struts2框架引入到應用中來,如代碼清單3-1所示:?
如果打開StrutsPrepareAndExecuteFilter的源碼,我們可以發現它只是一個實現了Filter接口的實現類。其方法列表如圖3-3所示:?
?
根據Servlet標準中Filter的生命周期的相關知識,我們知道Filter中所定義的方法,具有完全不同的執行時間段和生命周期,它們的執行互不影響,沒有交叉。而Filter的生命周期也成為我們對整個Struts2進行運行邏輯主線劃分的主要依據:?
- 第一條主線 —— Struts2的初始化 —— init方法驅動執行
- 第二條主線 —— Struts2處理Http請求 —— doFilter方法驅動執行
在這里,我們首先不對StrutsPrepareAndExecuteFilter的源碼做深入的探討,不過我們可以先把這個入口程序的基本結構和功能結合我們對Struts2劃分的兩條邏輯主線,用示意圖圖的形式表達出來,從而幫助讀者對入口程序的運行邏輯主線有個初步的認識,示意圖如圖3-4所示:?
從圖中,我們可以清晰地看到Struts2的兩條邏輯主線之間有一條分隔符分開。不同的邏輯主線,他們之間完全沒有交叉,驅動他們執行的時間節點和觸發條件都不同。因而,我們日后對Struts2運行邏輯的分析,也將圍繞著這兩條主線分別展開。?
Struts2入口程序的示意圖,可以看作是對Web容器黑盒模型的第一層細化,讀者在這里應該更多關心程序運行的基本方向,其內部細節,有待我們在之后的章節為大家一一解開其中的奧秘。?
3.3.1.2 Struts2的初始化主線?
Struts2的初始化主線發生在Web應用程序啟動之初,由入口程序的init方法驅動執行完成。這條運行主線主要特點有:?
僅在Web應用啟動時執行一次?
由于這條主線由Filter中的init方法驅動執行,執行完畢后,該主線結束。也就是說,這條主線本身不參與后任何的Http請求的處理過程,無論Struts2之后再收到多少Http請求,這條主線都不會重復執行。?
Init方法的執行失敗將導致整個Web應用啟動失敗?
如果在init方法執行的過程中發生異常,整個Web應用將無法啟動。這個特點從框架規范的角度規定了我們必須確保初始化過程的順利執行。因為在這個過程中,所以框架內部定義的元素將被初始化,并支撐起整個Struts2進行Http處理的過程。?
這兩大特點本身其實來源于Filter這個Servlet規范的基本運行特性。然而,這兩大特點卻也為應用程序在框架的基礎之上進行邏輯擴展提供了理論上的指導意見。在之后有關如何擴展框架的話題討論中,我們可以看到所有的擴展方案都將基于這兩大特點進行設計。?
那么,Struts2的初始化主線到底做了點什么呢?對應于Struts2初始化的運行特點,Struts2的初始化主線也有兩大主要內容:?
框架元素的初始化工作?
這一初始化工作包含了對框架內部的許多內置對象的創建和緩存。我們發現,對于框架初始化工作的基本要求,就是在整個框架的運行過程中僅被執行一次,這正好符合這條主線的基本特點。?
控制框架運行的必要條件?
框架的可擴展特性保證了我們可以在應用層面對框架的運行參數和執行模式進行定制化,而框架則有必要對這種定制化進行正確性校驗。當這種校驗失敗時,Web應用的啟動會失敗。這也就是Struts2在框架級別所能夠提供的運行期的檢查。?
初始化主線貫穿了Struts2對其內置對象的創建和緩存的過程,這一過程相當于把整個Struts2作為一個框架的運行環境完整地創建出來。這條主線的順利運行,為之后的Http請求處理主線提供了必要的框架運行環境。?
我們在這里所說的運行環境和Struts2自身的運行環境不同,它是指建立在Web服務器之上,框架自身運行所必須的內置對象的集合。為了更好地對這些內置對象進行管理,Struts2引入了框架級別“容器”的概念。因而Struts2的初始化主線,實際上最終轉化為對這個“容器”的初始化過程。有關這個“容器”的定義和初始化過程的細節,我們將在第五章中為讀者解開謎團。?
3.3.1.3 Struts2的Http請求處理主線?
Struts2的Http請求處理主線是Struts2的核心主線,包含了Struts2處理Http請求、進行必要的數據處理和處理數據返回的全部過程。這條主線將在任何滿足web.xml中所指定的URL Pattern的Http請求發生時進行響應,由doFilter方法負責驅動執行。?
如果我們回顧一下Struts2核心入口程序的流程圖(圖2-4),我們可以看到Struts2的Http請求處理主線又被一條分割線劃分成了兩個不同的執行階段:?
第一階段 —— Http請求預處理?
在這個階段中,程序執行的控制權在Struts2手上。這個階段的主要工作是針對每個Http請求進行預處理,為真正的業務邏輯執行做必要的數據環境和運行環境的準備。?
程序代碼在這個階段有一個非常顯著的特點:依賴于Web容器,并時時刻刻將與Web容器打交道作為主要工作。?
第二階段 —— XWork執行業務邏輯?
在這個階段,程序執行的控制權被移交給了XWork。Struts2在完成了Http請求的預處理之后,將Http請求中的數據封裝成為普通的Java對象,并由XWork負責執行具體的業務邏輯。?
程序代碼在這個階段的特點和第一階段完全相反:不依賴于Web容器,完全由XWork框架驅動整個執行的過程。?
從Struts2對于Http請求的處理過程中,我們可以看出Struts2的核心設計理念在于解耦。所謂解耦,實際上是盡可能地消除核心程序對外部運行環境的依賴,從而保證核心程序能夠更加專注于應用程序的邏輯本身。在Struts2中,我們所說的外部運行環境就是Web容器。我們在這里可以看到,Struts2的核心設計理念與Struts2的運行環境居然是一個矛盾體!?
這種設計實現與目的之間的矛盾,卻是Struts2的設計始終圍繞著Web開發中的最佳實踐的最有力證明,也是Struts2從設計理念開始,就優于其他表示層框架的精要所在。在解耦方面,Struts2也確實做到了2個不同的層面,從而使整個設計更加突顯出其優秀之處:?
從代碼上進行物理解耦?
Struts2將第一階段中的代碼整合到struts2-core-2.2.1.jar,而將第二階段中的代碼整合到xwork-core-2.2.1.jar。?
將邏輯分配到不同的執行階段?
Struts2將處理數據的邏輯和處理業務的邏輯分配到2個不同的執行階段,使得我們對于代碼邏輯的關注點更為清晰。?
因此,正如我們在之前的章節所談到的,嚴格意義上的Struts2,實際上由2個不同的框架所組成。一個是真正意義上的Struts2,另外一個是XWork。從職責上來說,XWork才是真正實現MVC的框架,Struts2的工作是在對Http請求進行一定處理后,委托XWork完成真正的邏輯處理。將Web容器與MVC實現分離,是Struts2區別于其他Web框架的最重要的特性,也是最值得我們品味的一個宏觀設計思路。當讀者真正理解了其中的奧秘,相信讀者也就會真正掌握Web開發之道了。?
3.3.2顯微鏡 —— Struts2的微觀元素?
在了解了Struts2的宏觀面之后,我們再來一起探究一下構成這些宏觀面的微觀元素。同樣的,不同的主線和不同的階段所承擔的職責不同,構成它們的微觀元素也不盡相同。在本節中,我們將列出每條主線和每個執行階段的主要組成元素。或許在這其中大家會接觸到許多新名詞,讀者不妨首先感性地認識一下這些概念性的名詞,可以不求甚解,因為我們會在后續的章節中對Struts2的這些元素一一展開分析和講解。?
3.3.2.1 第一條主線 —— Struts2的初始化?
在對Struts2初始化主線的宏觀分析中,我們曾經談到為了幫助更好地管理Struts2中的內置對象,Struts2引入了一個“容器”的概念,將所有需要被管理的對象全部置于容器之中。因而,整個Struts2初始化過程,也始終圍繞著這個“容器”展開。除了“容器”,Struts2中的另一類配置元素PackageConfig,也是Struts2初始化的主要內容之一。如果我們從“數據 + 行為”的角度來分析,那么構成Struts2整個初始化過程的主要元素,就可以被分為數據結構的定義和初始化行為的操作接口兩個部分。?
從數據結構定義的角度,“容器”順理成章地成為Struts2初始化主線中的核心構成元素,而PackageConfig作為事件請求映射的配置元素也成為了我們所需要重點關注的構成元素。它們的接口定義和實現類如表3-1所示:?
?
表3-1的定義,從數據結構的角度指出了Struts2初始化流程的主要對象是哪些。而整個初始化的操作過程,則由另外兩個相輔相成的元素配合共同完成,它們分別是加載接口(Provider)和構造器(Builder),其相關元素如表3-2所示:?
?
Struts2初始化主線中還有一些輔助的元素,它們主要被用于承載這些配置加載接口并在初始化時驅動整個初始化流程的順利執行。相關元素如表3-3所示:?
?
Struts2的初始化是一個非常復雜的流程。在這里我們僅僅給出了部分主要的數據結構和基礎操作接口。讀者可以使用IDE的源碼查看功能找到這些接口的眾多實現類。從這些實現類中,大家會發現這些實現類實際上是對整個Struts2配置元素的一個總串聯,之后的章節我們會通過源碼分析它們的聯系和運行機理。?
3.3.2.2第二條主線 —— 第一階段 —— Http請求預處理?
在這個階段,我們知道程序的執行控制權還控制在Struts2手中。所以在這個階段中所涉及到的主要微觀元素,都是Struts2的類。這些類的主要職責是與Web容器打交道。因而,從設計原則上,為了保持解耦,這個階段做了大量的對象創建和對象轉化的工作。當這些工作完成之后,就能交付第二個階段繼續執行。這個階段的主要微觀元素如表3-4所示:?
?
雖然這個階段所涉及到的元素很少,但是其中的Dispatcher卻是整個Struts2框架的核心。Dispatcher被稱之為核心分發器,是Struts2進行Http請求處理的實際場所。在整個處理流程中,Dispatcher不僅是Http請求預處理的實際執行者,更是將Http請求與Web容器進行解耦并進行邏輯處理轉發的執行驅動核心。事實上,我們對Struts2框架內部機理的研究,都將以Dispatcher作為重要的切入點而展開。?
3.3.2.2第二條主線 —— 第二階段 —— XWork執行業務邏輯?
在這個階段,程序的執行控制權被移交到了XWork框架中。我們可以想象位于這個執行階段的微觀元素區別于第一個階段的顯著特點:它們都是XWork框架所定義的類。其相關微觀元素的定義,如表3-5所示:?
?
在這里,我們形象地把XWork比喻成了一條生產流水線。在這其中的每個元素,就像是生產線中的重要組成部分。XWork框架就像一個完整的事件執行器,進入框架中的事件就如同進入生產線中的原材料,會按照生產線中的定義依次執行并產生結果。?
表3-5中的七個元素,被稱之為XWork的七大元素,貫穿了XWork事件執行器的整個生命周期。它們各司其職,精心配合,提供了事件執行框架足夠的擴展接口。不僅如此,它們之間的調用關系,也成為了XWork框架設計中的經典。這些元素的調用關系,如下圖3-5所示:?
?
這幅圖不僅包含了XWork框架中各個元素的調用關系,還把整個XWork框架置于Web容器這樣一個大的環境之中,同時給出了XWork框架的調用核心Dispatcher。我們在這里不再對這幅圖做深入的剖析,讀者可以大致了解XWork中這些元素的結構和層次關系。在第八章中,我們將從數據流和控制流這兩個不同的角度,對這張圖的程序流轉方向進行詳細的分析。
原文鏈接:[http://wely.iteye.com/blog/2295278]
總結
以上是生活随笔為你收集整理的多视角透析Struts2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果真要开发无线充电外壳 已要求联发科提
- 下一篇: 密织“地网” 南充“试水”智慧安防