天天看點

Struts2 源碼分析——調結者(Dispatcher)之action請求

章節簡言

上一章筆者講到關于struts2啟動的時候加載對應的準備工作。如加載配置檔案struts.xml之類的資訊。而相應的這些操作都離不開Dispatcher類的幫助。如果讀者隻是認為Dispatcher類的作用隻有這些。那真的是大錯特錯了。是以本章筆者将繼續講到關于Dispatcher類的另一個功能。即是StrutsPrepareFilter類倆項工作中的處理request請求相關資訊。在講解之前,筆者還是想把相關的資訊回想一下:當項目啟動的時候,strtus2也就啟動了。然後就會去初始化對應需要的資訊(這部分内容上一章已經講到了)。之後當使用者在網址上輸入通路的URL的時候。就會進入StrutsPrepareFilter類處理request請求的功能。好了。明白是什麼到這一步就可以了。因為下面就是要講到關于這一部分的内容。

調結者的action請求

StrutsPrepareFilter類在處理request請求的時候,需要用到一個叫PrepareOperations類的幫忙。PrepareOperations類可以說是StrutsPrepareFilter類和Dispatcher類的中間人。PrepareOperations類大部分的工作都是通過Dispatcher類完成的。先讓我們看一段代碼。如下

StrutsPrepareFilter類:

從上面的紅色代碼我們可以看出來,PrepareOperations類在執行個體化時候,接受Dispatcher類作為構造函數的參數。即是在struts2啟動加載準備工作之後初始化。那麼PrepareOperations類到底又做哪些工作呢?讓我們在看一下下面的代碼。如下

上面代碼我們可以看出PrepareOperations類總共做了五件事情。先讓筆者簡單的講解一下:當使用者的request請求過來的時候,會判斷一下request請求是不是被排除之外的。如果是,則把REQUEST_EXCLUDED_FROM_ACTION_MAPPING常量作為KEY,object執行個體作為值存放在request的Attrbute裡面。這是為後面的StrutsExecuteFilter類作準備(下一章筆者會講到)。如果不是,則進行request請求處理。如下

1.設定request請求的本地化和格式編碼。實作上還是Dispatcher類在做工作。代碼如下

PrepareOperations類:

Dispatcher類:

 2.建立Action上下文(ActionContext類),并把上下文存放在本地線程(ThreadLocal)。所謂的上下文可以了解為把相同性質的業務歸為一類。而上下文就是這一類和外部相交處。所有的資料操作都可以通過他還完成。當然上下文的定義在不同的地方有不同的意思。請讀者自行找閱資料。先讓我們看一下代碼。如下

從上面的紅色代碼我們就能夠看出第一次request請求就會建立一個新的action上下文(ActionContext)。同時也能明白ActionContext裡面存放大量的關于request請求對應的資料。而這些操作又離不開Dispatcher類的幫忙。最後把上下文(ActionContext類)存放到ActionContext類内部的本地線程(ThreadLocal)。代碼ActionContext.setContext(ctx)就是最好的說明。另外,上面有一點讓筆者一直不明白為什麼這麼做。覺得沒有什麼意義。即是獲得request的屬性為CLEANUP_RECURSION_COUNTER的值,然後進行計算操作的功能。筆者不得不将他了解為:用于計算request請求跳轉action的次數。就是一個request請求的生命周期通過了幾個action請求。如果不對的話,請讀者自行屏蔽。

3.把Dispatcher執行個體配置設定置到他内部的本地線程(ThreadLocal)。這一步主要是為了後面的StrutsExecuteFilter類的工作。讓我們看一下代碼吧。如下

4.把HttpServletRequest包裝為對應的StrutsRequestWrapper或是MultiPartRequestWrapper。主要是為了友善開發人員操作處理multipart而以。這裡比較簡單。筆者不想過的解釋。

5.找到對應action映射資訊(ActionMapping類)。這部分的工作筆者認為是比較重要的。因為他将是StrutsExecuteFilter類工作的核心點。那麼ActionMapping類又是什麼呢?他是struts.xml配置檔案上的action資訊。有了他struts2才能知道目前請求是哪一個action類。那麼相關的知識筆者會在後面的章節講到。讓我們看一下代碼。如下

當筆者看到紅色代碼的時候,不得不說一句。看!又離不開Dispatcher類。同時值得注意是的ActionMapper類。所有的struts.xml配置檔案的action資訊都在這個類上面。即是可以通過ActionMapper類找到對應的action映射資訊(ActionMapping)。進而找到對應的action類(使用者定義的action)。另外代碼request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping)這邊所做的事情。功能意思大家都能看得出來。那為什麼這麼做。主要還是因為後面的StrutsExecuteFilter類要用到。

從上面的五個事件中。筆者至少知道一點。Dispatcher類的工作真的很重要。而PrepareOperations類大部分隻是一個中間人而以。當然這是筆者自己的了解。

Dispatcher的結束處理

筆者本來想把這個知識點做一個章節來講。可是想太少了。為什麼是結束工作呢?不管是struts2啟動的準備工作。還是啟動成功後的action請求工作。struts2都會在工作結束之進行一些處理。先看一下struts2啟動的準備工作成完之後的處理。如下

StrutsPrepareFilter類的init方法:

InitOperations類:

從上面的代碼中我們可以看一個叫ContainerHolder類。這個類主要是用于存放Container容器。而上面在struts2啟動加載相關資訊的準備工作結束之後。把Container容器給冊除了。同時也去掉了上下文(ActionContext類)。

讓我們看一下request請求結束後做了什麼。如下

StrutsPrepareFilter類的doFilter方法:

從上面的紅色代碼我們知道他在request請求結束之後,把Container容器給冊除了。本地線程的Dispatcher類的執行個體删除了。上下文(ActionContext類)删除了。

到了這裡筆者就明白了一點:

1.struts2啟動的時候,加載相關的配置資訊。然後生成Dispatcher類的執行個體,初始化Container容器并把Dispatcher類的執行個體存放在PrepareOperations類裡面。那麼struts2的啟動準備工作結束,啟動成功。這時在把對應生成的Container容器和上下文(ActionContext類)删除掉。

注意:上下文(ActionContext類)在這個時候可能是沒有生成的。但他做了删除的工作。

2.啟動成功之後。使用者開始請求action。這個時候struts2會初始化一個新的Container容器和上下文(ActionContext類),配置設定Dispatcher類的執行個體到本地線程(ThreadLocal)中,找到對應的request請求的action映射(ActionMapping)并開始處理使用者對應的action請求。action請求成功之後,會删除對應的Container容器、本地線程的Dispatcher類的執行個體、上下文(ActionContext類)。即是一個請求,一個Container容器,一個上下文(ActionContext類)。一個本地線程的Dispatcher類的執行個體。

注意:删除Dispatcher類的執行個體是本地線程的。而不是PrepareOperations類的執行個體。(讀者不要搞錯了。然後一直會去想:删除了Dispatcher類的執行個體。又在哪裡建立了。不好意思。啟動的時候就建立,之後就在也沒有了。)

本章總結

關于StrutsPrepareFilter類的工作。還有Dispatcher的作用。相信讀者看到這裡的時候,心裡都會有一個大概念的想法。當然筆者并非會專業的寫書者。是以可能有些讀者或多或少很難去了解筆者的意思。請見諒。關于調結者(Dispatcher)之倆章,主要就是想讓讀者明白Dispatcher做了什麼。和StrutsPrepareFilter類有什麼關系。為後面學習StrutsExecuteFilter類的工作做準備。

繼續閱讀