深入Struts2_架構(gòu)與流程

1. Struts2與MVC

  • 1.1 基本的MVC架構(gòu)

模型-視圖-控制器或通常被稱為 MVC裁僧,是一種用于開(kāi)發(fā)web應(yīng)用程序的軟件設(shè)計(jì)模式.MVC模式由以下三個(gè)部分組成:
Model:模式的最低層,負(fù)責(zé)維護(hù)數(shù)據(jù).
View:負(fù)責(zé)顯示全部或部分的數(shù)據(jù)給用戶.
Controller: 控制模型和視圖之間的交互的軟件代碼.
MVC抽象用圖形表示如下:

mvc

  • 1.2 Struts2的MVC

Struts2是一個(gè)pull-MVC(或 MVC2)框架滩报。Struts 2 的模型-視圖-控制器模式由下面的五個(gè)核心部件實(shí)現(xiàn):
** 動(dòng)作,攔截器,值棧/OGNL,結(jié)果/結(jié)果類型,視圖技術(shù)**.

mvc2

控制器是由 Struts2調(diào)度servlet過(guò)濾器和攔截器實(shí)現(xiàn)的.
模型是由Action(包括ActionForm)實(shí)現(xiàn)的.
視圖是由JSp,FreeMaker等技術(shù)實(shí)現(xiàn)的,抽象成結(jié)果.
值棧/OGNL,結(jié)果/結(jié)果類型提供共同主線,連接和集成其他組件.

2. Struts架構(gòu)

2

這張圖很好地反應(yīng)了Struts2的整個(gè)框架.
FilterDispatcher:整個(gè)Struts2的調(diào)度中心(現(xiàn)在用StrutsPrepareAndExecuteFilter)锅知,也就是MVC中的C(控制中心),根據(jù)ActionMapper的結(jié)果來(lái)決定是否處理請(qǐng)求脓钾,如果ActionMapper指出該URL應(yīng)該被Struts2處理售睹,那么它將會(huì)執(zhí)行Action處理,并停止過(guò)濾器鏈上還沒(méi)有執(zhí)行的過(guò)濾器.
ActionMapper:會(huì)判斷這個(gè)請(qǐng)求是否應(yīng)該被Struts2處理可训,如果需要Struts2處理昌妹,ActionMapper會(huì)返回一個(gè)對(duì)象來(lái)描述請(qǐng)求對(duì)應(yīng)的ActionInvocation的信息.
ActionProxy:它會(huì)創(chuàng)建一個(gè)ActionInvocation代理實(shí)例,位于Action和xwork之間握截,使得我們?cè)趯?lái)有機(jī)會(huì)引入更多的實(shí)現(xiàn)方式飞崖,比如通過(guò)WebService來(lái)實(shí)現(xiàn)等.
ConfigurationManager:是xwork配置的管理中心,通俗的講谨胞,可以把它看做struts.xml這個(gè)配置文件在內(nèi)存中的對(duì)應(yīng).
struts.xml是Stuts2的應(yīng)用配置文件固歪,負(fù)責(zé)諸如URL與Action之間映射的配置、以及執(zhí)行后頁(yè)面跳轉(zhuǎn)的Result配置等.
ActionInvocation:真正調(diào)用并執(zhí)行Action胯努,它擁有一個(gè)Action實(shí)例和這個(gè)Action所依賴的攔截器實(shí)例.ActionInvocation會(huì)執(zhí)行這些攔截器牢裳、Action以及相應(yīng)的Result.類似于調(diào)度器.
Interceptor(攔截器):攔截器是一些無(wú)狀態(tài)的類,攔截器可以自動(dòng)攔截Action叶沛,它們給開(kāi)發(fā)者提供了在Action運(yùn)行之前或Result運(yùn)行之后來(lái)執(zhí)行一些功能代碼的機(jī)會(huì)蒲讯。類似于我們熟悉的javax.servlet.Filter.
Action:動(dòng)作類是Struts2中的動(dòng)作執(zhí)行單元。用來(lái)處理用戶請(qǐng)求灰署,并封裝業(yè)務(wù)所需要的數(shù)據(jù).
Result:Result就是不同視圖類型的抽象封裝模型判帮,不同的視圖類型會(huì)對(duì)應(yīng)不同的Result實(shí)現(xiàn),Struts2中支持多種視圖類型溉箕,比如Jsp晦墙,F(xiàn)reeMarker等.
Templates:各種視圖類型的頁(yè)面模板,比如JSP就是一種模板頁(yè)面技術(shù).
Tag Subsystem:Struts2的標(biāo)簽庫(kù)肴茄,它抽象了三種不同的視圖技術(shù)JSP晌畅、velocity、freemarker独郎,可以在不同的視圖技術(shù)中踩麦,幾乎沒(méi)有差別的使用這些標(biāo)簽.

3. Struts2運(yùn)行流程

  1. 用戶發(fā)出請(qǐng)求
    請(qǐng)求會(huì)被Tomcat接收到,Tomcat服務(wù)器來(lái)選擇處理這個(gè)請(qǐng)求的Web應(yīng)用氓癌,就是選擇哪一個(gè)web工程來(lái)處理這個(gè)請(qǐng)求.
  2. web容器去讀這個(gè)工程的web.xml
    在web.xml中進(jìn)行匹配,發(fā)現(xiàn)是由struts2的過(guò)濾器FilterDispatcher(StrutsPrepareAndExecuteFilter)來(lái)處理,找到該過(guò)濾器的實(shí)例(初始化).
  3. 找到FilterDispatcher,回調(diào)doFilter()
    通常情況下谓谦,web.xml文件中還有其他過(guò)濾器時(shí),F(xiàn)ilterDispatcher是放在濾器鏈的最后贪婉;如果在FilterDispatcher前出現(xiàn)了如SiteMesh這種特殊的過(guò)濾器反粥,還必須在SiteMesh前引用Struts2的ActionContextCleanUp過(guò)濾器.
  4. FilterDispatcher將請(qǐng)求轉(zhuǎn)發(fā)給ActionMapper
    ActionMapper負(fù)責(zé)識(shí)別當(dāng)前的請(qǐng)求是否需要Struts2做出處理.
  5. ActionMapper告訴FilterDispatcher,需要處理這個(gè)請(qǐng)求,建立ActionProxy
    FilterDispatcher會(huì)停止過(guò)濾器鏈以后的部分疲迂,所以通常情況下:FilterDispatcher應(yīng)該出現(xiàn)在過(guò)濾器鏈的最后才顿。然后建立一個(gè)ActionProxy對(duì)象,這個(gè)對(duì)象作為Action與xwork之間的中間層尤蒿,會(huì)代理Action的運(yùn)行過(guò)程.
  6. ActionProxy詢問(wèn)ConfigurationManager,讀取Struts.xml
    ActionProxy對(duì)象剛被創(chuàng)建出來(lái)的時(shí)候郑气,并不知道要運(yùn)行哪個(gè)Action,它手里只有從FilterDispatcher中拿到的請(qǐng)求的URL.這時(shí)候,它問(wèn)ConfigurationManager問(wèn)到底要運(yùn)行哪個(gè)Action.
    而ConfigurationManager就是負(fù)責(zé)讀取并管理struts.xml的腰池,可以簡(jiǎn)單的理解為ConfigurationManager是struts.xml在內(nèi)存中的映像.
    在服務(wù)器啟動(dòng)的時(shí)候尾组,ConfigurationManager會(huì)一次性的把struts.xml中的所有信息讀到內(nèi)存里,并緩存起來(lái)示弓,以保證ActionProxy拿著來(lái)訪的URL向他詢問(wèn)要運(yùn)行哪個(gè)Action的時(shí)候讳侨,就可以直接匹配、查找并回答了.
  7. ActionProxy建立ActionInvocation對(duì)象
    ActionProxy拿到了運(yùn)行哪個(gè)Action奏属、相關(guān)的攔截器以及所有可能使用的result信息跨跨,就可以著手建立ActionInvocation對(duì)象了,ActionInvocation對(duì)象描述了Action運(yùn)行的整個(gè)過(guò)程.
  8. 在execute()之前的攔截器
    在execute()之前會(huì)執(zhí)行很多默認(rèn)的攔截器.攔截器的運(yùn)行被分成兩部分囱皿,一部分在Action之前運(yùn)行勇婴,一部分在Result之后運(yùn)行,而且順序是剛好反過(guò)來(lái)的铆帽。也就是在Action執(zhí)行前的順序咆耿,比如是攔截器1、攔截器2爹橱、攔截器3萨螺,那么運(yùn)行Result之后,再次運(yùn)行攔截器的時(shí)候愧驱,順序就變成攔截器3慰技、攔截器2、攔截器1了组砚。
  9. 執(zhí)行execute()方法
  10. 根據(jù)execute方法返回的結(jié)果吻商,也就是Result,在struts.xml中匹配選擇下一個(gè)頁(yè)面
  11. 找到模版頁(yè)面,根據(jù)標(biāo)簽庫(kù)生成最終頁(yè)面
  12. 在execute()之后執(zhí)行的攔截器,和8相反
  13. ActionInvocation對(duì)象執(zhí)行完畢
    這時(shí)候已經(jīng)得到了HttpServletResponse對(duì)象了,按照配置定義相反的順序再經(jīng)過(guò)一次過(guò)濾器,向客戶端展示結(jié)果.

4. 再看Struts2架構(gòu)與流程

Struts2本身,也包含了真正意義上的Struts2與Xwork兩種框架.從職責(zé)上來(lái)說(shuō)糟红,XWork才是真正實(shí)現(xiàn)MVC的框架艾帐,Struts2的工作是在對(duì)Http請(qǐng)求進(jìn)行一定處理后乌叶,委托XWork完成真正的邏輯處理.將Web容器與MVC實(shí)現(xiàn)分離解耦,是Struts2的精妙之處

  • 4.1 Struts2部分

在第二節(jié)的框架圖中,過(guò)濾器部分均屬于Struts2部分.
包括StrutsPrepareFilterStrutsExecuteFilter,是StrutsPrepareAndExecuteFilter的兩部分.
前者是Struts2進(jìn)行Http請(qǐng)求的預(yù)處理,而后者是Struts2進(jìn)行Http請(qǐng)求的邏輯處理.
StrutsPrepareAndExecuteFilter自2.1.3替代FilterDispatcher.如果想自定義過(guò)濾器, 要放在strtus2過(guò)濾器之前,又想在執(zhí)行action之前拿filter做一些事,FilterDispatcher做不到.而StrutsPrepareAndExecuteFilter可以拆分成StrutsPrepareFilter和StrutsExecuteFilter,可以在這兩個(gè)過(guò)濾器之間加上自己的過(guò)濾器.

  • 4.2 XWork部分

在離開(kāi)web容器以后,就到了Xwork部分,執(zhí)行業(yè)務(wù)邏輯.它包括了ActionProxy,ActionInvocation,Interceptor,Action,ActionContext,ValueStack,Result七個(gè)元素.

xwork

該圖很直觀地描繪了Xwork的整體架構(gòu)(不包括Dispatcher),包括了第二節(jié)架構(gòu)圖中的大部分,我們稱之為控制流元素.另外增加了ActionContext與ValueStack這樣的數(shù)據(jù)流元素.
關(guān)于控制流元素,在第二節(jié)已有相關(guān)介紹,接下來(lái)看看數(shù)據(jù)流元素的內(nèi)容:
ActionContext-數(shù)據(jù)環(huán)境
ActionContext是一個(gè)獨(dú)立的數(shù)據(jù)結(jié)構(gòu)柒爸,其主要作用是為XWork的執(zhí)行提供數(shù)據(jù)環(huán)境准浴。無(wú)論是請(qǐng)求的參數(shù),還是處理的返回值捎稚,甚至一些原生的Web容器對(duì)象乐横,都被封裝于ActionContext的內(nèi)部,成為了Struts2 / XWork執(zhí)行時(shí)所依賴的數(shù)據(jù)基礎(chǔ).職責(zé)在于數(shù)據(jù)存儲(chǔ).
ValueStack-數(shù)據(jù)訪問(wèn)環(huán)境
ValueStack本身是一個(gè)數(shù)據(jù)結(jié)構(gòu)今野,其主要作用是用以對(duì)OGNL計(jì)算進(jìn)行擴(kuò)展葡公。因而,位于ActionContext之中的ValueStack則賦予了ActionContext進(jìn)行數(shù)據(jù)計(jì)算的功能条霜,從而使得ValueStack自身成為了一個(gè)可以進(jìn)行數(shù)據(jù)訪問(wèn)的環(huán)境.職責(zé)在于數(shù)據(jù)傳輸.

  • 4.3 Struts2初始化

第二節(jié)的圖對(duì)應(yīng)當(dāng)請(qǐng)求發(fā)生時(shí)候的過(guò)程.那么這一整個(gè)初始的框架是怎么產(chǎn)生的呢.其實(shí)在Struts2框架處理http請(qǐng)求,Xwork框架處理業(yè)務(wù)邏輯之前,還需要Struts2框架的初始化過(guò)程.
StrutsPrepareAndExecuteFilter是整個(gè)框架的入口點(diǎn),在初始化時(shí)候調(diào)用init()方法.

  public void init(FilterConfig filterConfig) throws ServletException {
       InitOperations init = new InitOperations();//類似一個(gè)工具類催什,包含了一些初始化操作
       Dispatcher dispatcher = null;//Dispatcher:Struts2的核心分發(fā)器
       try {
           /**
            * 封裝filterConfig,提供了一個(gè)便利的方法
            * getInitParameterNames()蛔外,將枚舉類型的參數(shù)轉(zhuǎn)換成Iterator(EnumerationIterator)
            */
           FilterHostConfig config = new FilterHostConfig(filterConfig);
           init.initLogging(config);//初始化日志
           //初始化Dispatcher
           dispatcher = init.initDispatcher(config);
           init.initStaticContentLoader(config, dispatcher);//初始化靜態(tài)文件加載器

           prepare = new PrepareOperations(dispatcher);//初始化HTTP預(yù)處理的操作類
           execute = new ExecuteOperations(dispatcher);//初始化進(jìn)行HTTP請(qǐng)求處理的邏輯執(zhí)行操作類
           this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

           postInit(dispatcher, filterConfig);//回調(diào)方法,留作用戶拓展
       } finally {
           if (dispatcher != null) {
               dispatcher.cleanUpAfterInit();
           }
           init.cleanup();
       }
   }

可以看到大致的初始化過(guò)程分為以下幾步:

  1. 封裝FilterConfig->FilterHostConfig
  2. 初始化日志操作
  3. 初始化核心分發(fā)器Dispatcher
  4. 初始化靜態(tài)文件加載器,packages,該參數(shù)用來(lái)配置自動(dòng)搜尋目錄
  5. 初始化PrepareOperations和ExecuteOperations.

其中我們?cè)賮?lái)看核心分發(fā)器Dispatcher的初始化過(guò)程:

  public void init() {
      //初始化配置文件管理器
      if (configurationManager == null) {
          //根據(jù)name進(jìn)行對(duì)象尋址
          //DEFAULT_BEAN_NAME = "struts"
          //<bean type="org.apache.struts2.dispatcher.DispatcherErrorHandler" name="struts".../>
          //<bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
          configurationManager = createConfigurationManager(DefaultBeanSelectionProvider.DEFAULT_BEAN_NAME);
      }

      try {
          init_FileManager(); //初始化文件管理器

          // 初始化Struct2的默認(rèn)配置加載器:
          // org/apache/struts2/default.properties蛆楞,
          // 如果項(xiàng)目中需要覆蓋,可以在classpath里的struts.properties里覆寫
          init_DefaultProperties(); // [1]
          //初始化Xml配置加載器:
          // 如struts-default.xml,struts-plugin.xml,struts.xml
          init_TraditionalXmlConfigurations(); // [2]
          //初始化Properties配置加載器
          init_LegacyStrutsProperties(); // [3]
          //初始化用戶自定義的配置加載器
          init_CustomConfigurationProviders(); // [5]
          //初始化由web.xml傳入的參數(shù)
          init_FilterInitParameters() ; // [6]
          //初始化容器內(nèi)置的對(duì)象
          //eg:ObjectFactory,FreemarkerManager....
          init_AliasStandardObjects() ; // [7]
          //創(chuàng)建容器, 初始化并預(yù)加載配置
          Container container = init_PreloadConfiguration();
          //對(duì)容器進(jìn)行依賴注入
          container.inject(this);
          //檢查對(duì)WebLogic的特殊支持
          init_CheckWebLogicWorkaround(container);
          //初始化所有的DispatcherListener
          if (!dispatcherListeners.isEmpty()) {
              for (DispatcherListener l : dispatcherListeners) {
                  l.dispatcherInitialized(this);
              }
          }
          //初始化錯(cuò)誤處理器
          errorHandler.init(servletContext);

      } catch (Exception ex) {
          if (LOG.isErrorEnabled())
              LOG.error("Dispatcher initialization failed", ex);
          throw new StrutsException(ex);
      }
  }

這里還可以分為四部:

  1. 初始化ConfigurationManager
  2. 初始化配置加載器.常用的配置文件加載順序如
    a. default.properties
    b. struts-default.xml
    c. struts-plugin.xml
    d. struts.xml
    e. struts.properties
    f. web.xml
  3. 初始化容器(創(chuàng)建容器,依賴注入)
  4. 額外的初始化工作(初始化WebLogic配置,執(zhí)行DispatcherListner的配置..)

4.4 再看Struts2流程

根據(jù)上面的總結(jié),從一個(gè)更高的抽象角度看,我們把流程分為三部分,也即初始化部分,Struts2處理http請(qǐng)求部分,Xwork處理業(yè)務(wù)邏輯部分.

liu

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末夹厌,一起剝皮案震驚了整個(gè)濱河市豹爹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌矛纹,老刑警劉巖臂聋,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異或南,居然都是意外死亡孩等,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門采够,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人权她,你說(shuō)我怎么就攤上這事逝薪∮缫” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵董济,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)欢搜,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任谴轮,我火速辦了婚禮狂巢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己藻雌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布驯杜。 她就那樣靜靜地躺著做个,像睡著了一般。 火紅的嫁衣襯著肌膚如雪居暖。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天糯景,我揣著相機(jī)與錄音省骂,去河邊找鬼。 笑死怠惶,一個(gè)胖子當(dāng)著我的面吹牛轧粟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播览妖,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼揽祥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拄丰?” 一聲冷哼從身側(cè)響起俐末,我...
    開(kāi)封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤卓箫,失蹤者是張志新(化名)和其女友劉穎垄潮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體弯洗,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牡整,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谣辞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沐扳。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖歉闰,靈堂內(nèi)的尸體忽然破棺而出卓起,到底是詐尸還是另有隱情,我是刑警寧澤戏阅,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布奕筐,位于F島的核電站,受9級(jí)特大地震影響离赫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旬盯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望接剩。 院中可真熱鬧萨咳,春花似錦、人聲如沸培他。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腾降。三九已至碎绎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奸晴,已是汗流浹背日麸。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墩划,地道東北人嗡综。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像极景,于是被迫代替她去往敵國(guó)和親察净。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盼樟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產(chǎn)品晨缴,是在 struts1和WebWork的...
    inke閱讀 2,256評(píng)論 0 50
  • 1、struts2工作流程 Struts 2框架本身大致可以分為3個(gè)部分: 核心控制器FilterDispatch...
    重山楊閱讀 1,520評(píng)論 0 38
  • action中如何接受頁(yè)面?zhèn)鬟^(guò)來(lái)的參數(shù) 第一種情況:(同名參數(shù)) 例如:通過(guò)頁(yè)面要把id=1 name=tom a...
    清楓_小天閱讀 2,958評(píng)論 1 22
  • 本文包括: 1棋返、Struts 2 概述2雷猪、Struts 2 快速入門3、Struts 2 的執(zhí)行流程4求摇、配置 st...
    廖少少閱讀 2,960評(píng)論 3 13
  • 概述 Struts就是基于mvc模式的框架与境!(struts其實(shí)也是servlet封裝,提高開(kāi)發(fā)效率摔刁!) Strut...
    奮斗的老王閱讀 2,940評(píng)論 0 51