Struts2中的Action
多數(shù)的MVC框架中的Control層,都是一個(gè)Java對(duì)象。按照慣例,我們通常會(huì)把這個(gè)層次上面的Java對(duì)象統(tǒng)稱為Action層。本篇文章,我們就來簡(jiǎn)單介紹一下Struts2中Action的相關(guān)內(nèi)容。?
Action的定義?
傳統(tǒng)的MVC框架中,Control層一般都是一個(gè)類似與Servlet的一個(gè)Java對(duì)象。因?yàn)閺穆氊?zé)上講,Control層需要完成以下的職責(zé):?
1. 接收從Web容器傳遞過來的參數(shù),并做恰當(dāng)?shù)念愋娃D(zhuǎn)化?
2. 調(diào)用邏輯處理?
3. 搜集數(shù)據(jù),并返回到視圖?
而在這個(gè)其中的第一步和第三步,都離不開Web容器中的對(duì)象的處理。?
Struts2中的Action,與其他傳統(tǒng)的MVC框架不同,使用了XWork的Action來構(gòu)造Control層。讓我們首先來看看Action的接口定義:?
我們只需要實(shí)現(xiàn)這個(gè)接口,就可以在其中編寫業(yè)務(wù)邏輯完成我們的功能。?
在這個(gè)接口定義中,我們可以明顯看到與傳統(tǒng)的MVC框架之間的區(qū)別:Struts2中的Action,并不需要依賴于特定的Web容器。我們看不到類似HttpServletRequest,HttpServletResponse等Web容器相關(guān)的對(duì)象。?
而這一點(diǎn),也帶來了問題:?
提問:Struts2的Action并不帶有任何Web容器相關(guān)的對(duì)象,Action又是如何工作在Web容器中的呢??
雖然Struts2的Action只是一個(gè)非常普通的Java對(duì)象,并不具備任何Web容器的特質(zhì),但是我們需要把Action放到一個(gè)更加大的環(huán)境中來看。事實(shí)上,Struts2為Action的執(zhí)行,準(zhǔn)備了完整的數(shù)據(jù)環(huán)境和執(zhí)行環(huán)境。而這個(gè)執(zhí)行環(huán)境,就保證了Action在Web容器中的順利運(yùn)行。?
在Struts2中,每個(gè)Http的請(qǐng)求,會(huì)被發(fā)送到一個(gè)Filter。而這個(gè)Filter,就會(huì)針對(duì)每個(gè)請(qǐng)求,創(chuàng)建出一個(gè)代碼的執(zhí)行環(huán)境,并在這個(gè)基礎(chǔ)上,為每個(gè)執(zhí)行環(huán)境配備與之對(duì)應(yīng)的數(shù)據(jù)環(huán)境,這個(gè)數(shù)據(jù)環(huán)境中的內(nèi)容,就來自于Web容器中的一個(gè)又一個(gè)對(duì)象。這樣,就能夠順利調(diào)用Action執(zhí)行代碼而無需擔(dān)心它是否運(yùn)行在Web容器中了。?
至于這個(gè)執(zhí)行環(huán)境和數(shù)據(jù)環(huán)境到底是什么,我們接下來會(huì)詳細(xì)講到。?
提問:Struts2的Action并不帶有任何Web容器相關(guān)的對(duì)象,Action中又如何與Web容器進(jìn)行通信并獲取Web容器的相關(guān)對(duì)象呢??
剛剛我們提到Struts2會(huì)為每個(gè)Http的請(qǐng)求建立一個(gè)執(zhí)行環(huán)境和數(shù)據(jù)環(huán)境。其中,數(shù)據(jù)環(huán)境就成為了Action獲取Web容器的基礎(chǔ)。所以,當(dāng)Action需要獲取Web容器的相關(guān)對(duì)象,需要通過數(shù)據(jù)環(huán)境來進(jìn)行。?
Struts2的Action的這一個(gè)重要特性,至少能為我們帶來以下好處:?
1. 使得Struts2的Action非常易于測(cè)試?
如果我們完全不考慮Action的執(zhí)行環(huán)境,僅僅把Action看作一個(gè)普通的Java對(duì)象,那么我們甚至可以直接new一個(gè)Action的對(duì)象,通過執(zhí)行其中的方法完成測(cè)試。這樣,我們就不需要任何的Mock,來模擬Web容器的環(huán)境。?
2. 結(jié)合Action的執(zhí)行環(huán)境,使得Struts2在Control這個(gè)層次上,能夠定義更加豐富的執(zhí)行層次?
因?yàn)锳ction是一個(gè)普通的Java類,而不是一個(gè)Servlet類,完全脫離于Web容器,所以我們就能夠更加方便地對(duì)Control層進(jìn)行合理的層次設(shè)計(jì),從而抽象出許多公共的邏輯,并將這些邏輯脫離出Action對(duì)象本身。事實(shí)上,Struts2也正是這么做的,無論是Interceptor,還是Result,其實(shí)都是抽象出了Action中公共的邏輯部分,將他們放到了Action的外面,從而更加簡(jiǎn)化了Action的開發(fā)。?
3. 使得Struts2的Action看上去更像一個(gè)POJO,從而更加易于管理?
Struts2的Action是一個(gè)線程安全的對(duì)象。而Web容器傳遞過來的參數(shù),也會(huì)傳遞到Action中的成員變量中。這樣,Action看上去就更像一個(gè)POJO,從而能夠方便的被許多對(duì)象容器進(jìn)行管理。比如說,你可以非常方便得把Action納入到Spring的容器中進(jìn)行管理。?
Action的生命周期?
接下來,我們?cè)賮砜纯碨truts2中的Action的生命周期:?
?
這張圖來自于Struts2的Reference,我們能夠在圖中看到許多我們不熟悉的名詞,比如ActionProxy,Interceptor等等。這些都是Struts2的Control層的重要元素,也是Struts2的Control層的一個(gè)層次化的體現(xiàn)。?
上面的這張圖基本上能夠概括了Struts2的整個(gè)生命周期。接下來,我們就對(duì)Action中的一些重要元素進(jìn)行簡(jiǎn)單的描述。?
Action的五大元素?
在大概了解了Struts2的Action后,我們來重點(diǎn)研究一下在Struts2的Action周圍,為Action進(jìn)行服務(wù)的一些重要元素,這些元素將涵蓋Action的數(shù)據(jù)環(huán)境,Action的執(zhí)行環(huán)境、Action的調(diào)度者、Action的層次結(jié)構(gòu)和Action的執(zhí)行結(jié)果。?
ActionContext —— 數(shù)據(jù)環(huán)境?
之前我們提到了Struts2的Action并不是一個(gè)Servlet,它是脫離了Web容器的。但是對(duì)于一個(gè)Web框架來說,所有的數(shù)據(jù)請(qǐng)求(Request)和數(shù)據(jù)返回(Response)都來源于Web容器,那么Action在執(zhí)行的時(shí)候,如何去獲取這些數(shù)據(jù)呢??
這個(gè)問題的答案就在于,我們需要為每個(gè)Action準(zhǔn)備一個(gè)數(shù)據(jù)環(huán)境,這個(gè)數(shù)據(jù)環(huán)境被稱之為:ActionContext。由于Action是應(yīng)對(duì)于一個(gè)又一個(gè)的URL請(qǐng)求,所以ActionContext應(yīng)該具備以下的特性:?
1. ActionContext應(yīng)成為Action與Web容器之間的橋梁?
2. ActionContext中應(yīng)該保存有針對(duì)某個(gè)請(qǐng)求的詳細(xì)信息?
3. ActionContext應(yīng)該是一個(gè)線程安全的類對(duì)象?
Interceptor —— 豐富的層次結(jié)構(gòu)?
簡(jiǎn)單回顧一下上面所提到的Action的職責(zé),我們看到,需要在Action這個(gè)層面上完成的事情還不少。而完成這些職責(zé),就需要我們對(duì)這些職責(zé)進(jìn)行合理的分類和排序,將他們組織成有序的執(zhí)行隊(duì)列。在Struts2中,使用了一種類似責(zé)任鏈的設(shè)計(jì)模式對(duì)這些不同的職責(zé)進(jìn)行分類并串聯(lián)起來,從而使得Action層具備了豐富的層次結(jié)構(gòu)。而在這個(gè)執(zhí)行隊(duì)列中的每個(gè)元素,就被我們稱之為Interceptor,也就是攔截器。?
攔截器是AOP中的概念,它本身是一段代碼,可以通過定義“織入點(diǎn)”,來指定攔截器的代碼在“織入點(diǎn)”的前后執(zhí)行,從而起到攔截的作用。正如上面Struts2的Reference中講述的,Struts2的Interceptor,其攔截的對(duì)象是Action代碼,可以定義在Action代碼之前或者之后執(zhí)行攔截器的代碼。?
如果仔細(xì)留意一下Action LifeCycle圖中的Interceptor和Action的部分,我們可以看到,Interceptor一層一層的把Action包了起來。這是一個(gè)典型的堆棧結(jié)構(gòu),在代碼執(zhí)行的時(shí)候,每個(gè)Interceptor不僅需要文成它自身的邏輯,還通過遞歸調(diào)用負(fù)責(zé)下一個(gè)攔截器或Action的調(diào)用。?
也正如Struts2的Reference所說,Struts2提供的絕大多數(shù)的功能支持,都通過Interceptor來實(shí)現(xiàn),這些Interceptor可以隨意進(jìn)行配置,并且能夠方便的插入到程序中去運(yùn)行。?
Result —— 執(zhí)行結(jié)果?
有執(zhí)行就必然有執(zhí)行的結(jié)果。在Struts2中,Action的執(zhí)行結(jié)果被抽象成了一個(gè)層次。在這個(gè)層次中,可以定義任意類型的View層的結(jié)構(gòu)。也就是說,Struts2并不強(qiáng)制View層的表現(xiàn)形式,可以是JSP、Freemarker模板、二進(jìn)制流輸出等等。?
Struts2把執(zhí)行結(jié)果抽象成一個(gè)層次,使得你可以不再關(guān)注許多視圖整合上面的細(xì)節(jié),只需要考慮視圖的類型和數(shù)據(jù)的準(zhǔn)備,這樣,你也可以不必在沉浸在雜亂的構(gòu)造視圖的代碼中。?
ActionProxy —— 執(zhí)行環(huán)境?
有了攔截器Interceptor,有了Action本身,也有了Action的執(zhí)行結(jié)果Result,我們就需要一個(gè)類似調(diào)度器的產(chǎn)品,將這些元素整合起來,進(jìn)行調(diào)度執(zhí)行。在上面的Action Lifecyle的圖中,我們可以看到,Interceptor、Action和Result都處于ActionProxy中,所以ActionProxy就成為了所有這些元素的執(zhí)行環(huán)境。?
既然是執(zhí)行環(huán)境,那么ActionProxy就需要提供Action執(zhí)行的時(shí)候一切所需要的配置、參數(shù)等等,當(dāng)然,也要有進(jìn)行Action調(diào)用的入口。所以讓我們來看一下ActionProxy的接口:?
很顯然,在這其中,prepare和execute方法是用作Action調(diào)用的入口函數(shù),其他的接口定義都與Action執(zhí)行時(shí)的運(yùn)行參數(shù)和配置有關(guān)。?
ActionInvocation —— 調(diào)度者?
在上面的ActionProxy的接口定義中,我們可以看到有一個(gè)比較特殊的變量:ActionInvocation比較吸引我們的眼球。從字面上去理解,ActionInvocation就是Action的調(diào)用者。事實(shí)上也是如此,ActionInvocation在這個(gè)Action的執(zhí)行過程中,負(fù)責(zé)Interceptor、Action和Result等一系列元素的調(diào)度。?
在之后的章節(jié)中,這個(gè)ActionInvocation類也將成為我們解讀Struts2源碼的一個(gè)重要入手點(diǎn)。這個(gè)類將告訴你,Struts2是如何通過ActionInvocation來實(shí)現(xiàn)對(duì)Interceptor、Action和Result的合理調(diào)度的。
原文鏈接:[http://wely.iteye.com/blog/2295296]
總結(jié)
以上是生活随笔為你收集整理的Struts2中的Action的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英国电价与光伏容量占比关系分析
- 下一篇: 让智能家居产品操控更简单 快捷键来了