Struts2請求處理源碼分析

當用戶向Struts2發送請求時,FilterDispatcher的doFilter()方法自動調用,doFilter()方法處理請求過程,以下:html

1. 建立值棧對象stack;程序員

2. 建立Action上下文對象;web

3. 對請求進行從新封裝,這次封裝根據請求內容的類型不一樣,返回不一樣的對象:app

若是爲multipart/form-data類型,則返回MultiPartRequestWrapper類型的對象,該對象服務於文件上傳,不然返回StrutsRequestWrapper類型的對象,MultiPartRequestWrapper是StrutsRequestWrapper的子類,而這兩個類都是HttpServletRequest接口的實現。jsp

4. 經過actionMapper.getMapping()得到ActionMapping對象,Action的配置信息存儲在ActionMapping對象中(Action的配置信息:Action的name、namespace和要調用的方法method)。相關代碼以下圖所示:spa

clip_image002

以上代碼,活動圖以下:.net

clip_image004

5. 若是getMapping()方法返回ActionMapping對象爲null,則FilterDispatcher認爲用戶請求不是Action,此時FilterDispatcher會首先分析:代理

若是請求以/struts開頭,會自動查找在web.xml文件中配置的packages初始化參數,FilterDispatcher會將packages參數值包下的文件看成靜態資源處理,即直接在頁面上顯示文件內容。日誌

若是用戶請求的資源不是以/struts開頭—多是.jsp文件,也多是.html文件,則經過過濾器鏈繼續往下傳送,直到到達請求的資源爲止。orm

6. 若是getMapping()方法返回有效的ActionMapping對象,則被認爲正在請求某個Action,將調用Dispatcher.serviceAction(request, response, servletContext, mapping)方法。

以上六步,相關代碼以下圖所示:

clip_image006

clip_image008

以上代碼,活動圖以下:

clip_image010

7. 請求進入dispatcher.serviceAction(request,response,servletContext,mapping)方法中:

a) 將相關對象信息封裝爲Map(如:HttpServletRequest、Http parameters、HttpServletResponse、HttpSession、ServletContext、ActionMapping等對象信息),並存入到執行上下文Map中,返回執行上下文Map對象extraMap;

b) 獲取mapping對象中存儲的action命名空間、name屬性、method屬性等信息;

c) 加載並解析Struts2配置文件,若是沒有人爲配置,默認按順序加載struts-default.xml、struts-plugin.xml、struts.xml,將action配置、result配置、interceptor配置,解析並存入至config對象中,返回文件配置對象config;

d) 根據執行上下文Map、action命名空間、name屬性、method屬性等建立用戶Action的代理對象;

e) 執行Action代理對象proxy.execute()方法,並轉向結果;

以上步驟相關代碼,如圖所示:

clip_image012

8. 執行Action代理對象proxy.execute()方法,該方法的執行,其實就是調用了invocation.invoke()方法,以下圖所示:

clip_image014

9. 執行invocation.invoke()方法,實現了截攔器的遞歸調用和執行Action的execute()方法,DefaultActionInvocation.invoke()方法中代碼,以下圖所示:clip_image016

在以上代碼中,並未看出攔截器的遞歸調用,實際上是否遞歸調用,是由程序員來控制的,遞歸調用實現很簡單:

a) 首先看下Interceptor接口定義:

clip_image018

b) 全部的截攔器必須實現intercept方法,而該方法的參數偏偏又是ActionInvocation,因此若是在intercept方法中調用invocation.invoke(),則會繼續從Action的Intercepor列表中找到下一個截攔器執行,依此遞歸調用Intercepor;

Struts2中的日誌攔截器LoggingInterceptor,以下圖所示:

clip_image020

c) 攔截器遞歸調用活動圖,以下所示:

clip_image022

10. 在invocation.invoke()方法中,執行攔截器、action並得到resultCode完畢後,則會繼續執行PreResultListener集合,並生成Result對象,實現PreResultListener接口,可在返回Result以前,作些自定義處理,如圖所示:

clip_image024

在返回Result以前,經過PreResultListener實現自定義處理,經常使用的有兩種方式:一種在Interceptor中實現,一種在Action實現,如圖所示:

clip_image026

clip_image028

以上兩種方式,你們能夠發現都是經過匿名內部類的方式實現,其實還有一種方式就是經過在攔截器中實現PreResultListener接口,並實現方法beforeResult方法,便可。以下圖所示:

clip_image030

11. 最後,經過生成Result完成用戶響應;

以上1-11步,爲Struts2處理請求的完整流程分析,其相關代碼調用流程,以下圖所示:

clip_image032

相關文章
相關標籤/搜索