當用戶向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
以上代碼,活動圖以下:.net
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)方法。
以上六步,相關代碼以下圖所示:
以上代碼,活動圖以下:
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()方法,並轉向結果;
以上步驟相關代碼,如圖所示:
8. 執行Action代理對象proxy.execute()方法,該方法的執行,其實就是調用了invocation.invoke()方法,以下圖所示:
9. 執行invocation.invoke()方法,實現了截攔器的遞歸調用和執行Action的execute()方法,DefaultActionInvocation.invoke()方法中代碼,以下圖所示:
在以上代碼中,並未看出攔截器的遞歸調用,實際上是否遞歸調用,是由程序員來控制的,遞歸調用實現很簡單:
a) 首先看下Interceptor接口定義:
b) 全部的截攔器必須實現intercept方法,而該方法的參數偏偏又是ActionInvocation,因此若是在intercept方法中調用invocation.invoke(),則會繼續從Action的Intercepor列表中找到下一個截攔器執行,依此遞歸調用Intercepor;
Struts2中的日誌攔截器LoggingInterceptor,以下圖所示:
c) 攔截器遞歸調用活動圖,以下所示:
10. 在invocation.invoke()方法中,執行攔截器、action並得到resultCode完畢後,則會繼續執行PreResultListener集合,並生成Result對象,實現PreResultListener接口,可在返回Result以前,作些自定義處理,如圖所示:
在返回Result以前,經過PreResultListener實現自定義處理,經常使用的有兩種方式:一種在Interceptor中實現,一種在Action實現,如圖所示:
以上兩種方式,你們能夠發現都是經過匿名內部類的方式實現,其實還有一種方式就是經過在攔截器中實現PreResultListener接口,並實現方法beforeResult方法,便可。以下圖所示:
11. 最後,經過生成Result完成用戶響應;
以上1-11步,爲Struts2處理請求的完整流程分析,其相關代碼調用流程,以下圖所示: