1 Struts 2的核心機制 web
Struts 2的處理流程已經和Struts 1截然不同了,可是和WebWork比較類似,這都是由於Struts 2和WebWork合併的緣故,並吸收了WebWork大部分設計思想。下面講解Struts 2的核心流程,以及其餘一些處理機制。 apache
2 FilterDispatcher處理流程 瀏覽器
在Struts 2中,最重要的一個類是org.apache.struts2.dispatcher.FilterDispatcher,從前面的示例能夠看出,用戶通 過瀏覽器提交一個(HttpServletRequest)請求後,請求被在web.xml中定義的過濾器FilterDispatcher攔截,在 FilterDispatcher中主要通過大概3層過濾器的處理,分別是ActionContext CleanUp、其餘過濾器(Othter Filters、SiteMesh等)、FilterDispatcher。 app
在FilterDispatcher過濾器中首先詢問ActionMapper是否須要調用某個Action來處理請求,若是 ActionMapper決定須要調用某個Action,FilterDispatcher則把請求的處理交給 ActionProxy,ActionProxy經過配置文件struts.xml找到須要調用的Action類,而後ActionProxy建立一個 ActionInvocation實例並調用該Action,但在調用以前,ActionInvocation會根據配置加載Action相關的全部 Interceptor,等Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果 result。 模塊化
在詳細介紹FilterDispatcher以前,先講解一下Servlet中過濾器的概念,以使讀者對此有一個深刻的認識。過濾器提供一種面向對 象的模塊化機制,用以將公共任務封裝到可插入的組件中,這些組件經過一個配置文件來聲明並動態地處理。實現一個過濾器須要3個步驟:首先編寫過濾器實現類 的程序,而後把該過濾器添加到web.xml 中聲明,最後把過濾器與應用程序一塊兒打包並部署。 this
過濾器 API 一共包含 3 個簡單的接口:Filter、FilterChain 和 FilterConfig。過濾器類必須實現 Filter 接口: 編碼
init():這個方法在容器實例化過濾器時被調用,它主要設計用於使過濾器爲處理作準備。容器爲這個方法傳遞一個FilterConfig,其中包含有配置信息。 url
doFilter():與Servlet擁有一個service()方法來處理請求同樣,過濾器擁有單個用於處理請求和響應的方法 doFilter()。這個方法接收3個輸入參數: ServletRequest、ServletResponse和FilterChain。FilterChain對於正確的過濾操做相當重 要,doFilter()方法必須調用FilterChain的doFilter()方法,除非該方法用來攔截之後的下游處理。 spa
destroy():該方法由容器在銷燬過濾器實例以前調用,以便可以執行任何須需的清理代碼。 設計
過濾器經過 web.xml 文件中的兩個XML標籤來聲明。<filter>標籤訂義過濾器的名稱,而且聲明實現類和init()參數。<filter- mapping>標籤將過濾器與Servlet或URL模式相關聯。<filter>標籤負責把一個過濾器名和一個特定的類關聯起來, 這種關聯是經過<filter-name>和<filter-class>元素指定的。<filter>必須有一 個<ulr-pattern>或者<servlet-name>元素,能夠經過<ulr-pattern>來指定通 配符,將過濾器應用到Web資源範圍;也能夠經過<servlet-name>將過濾器指定到某一個特定的Servlet上。應該注意這些聲 明的順序,所引用的過濾器名必須在前面的過濾器定義中給出。下面給出一個過濾器配置的示例代碼。
- <!--編碼過濾器-->
- <filter>
- <filter-name>SetCharacterEncoding</filter-name>
- <filter-class>
- com.gd.web.filter.GdSetCharacterEncodingFilter
- </filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>GBK</param-value>
- </init-param>
- <init-param>
- <param-name>ignore</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- <!--過濾全部的訪問-->
- <filter-mapping>
- <filter-name>SetCharacterEncoding</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
然也能夠配置多個過濾器,多個過濾器將按照配置的順序執行。
經過上面的介紹,相信讀者對過濾器會有一個深刻的瞭解。打開FilterDispatcher的源代碼能夠看到,FilterDispatcher 也一樣遵循這樣的原則,一樣實現了init()、doFilter ()、destroy()這3個接口,在init()接口裏主要實現了建立Dispatcher和設置默認包的功能,示例代碼以下:
- public void init(FilterConfig filterConfig) throws ServletException {
- try {
- this.filterConfig = filterConfig;
- //初始化日誌
- initLogging();
- //建立一個Dispatcher
- dispatcher = createDispatcher(filterConfig);
- dispatcher.init();
- dispatcher.getContainer().inject(this);
- //設定默認包
- staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));
- } finally {
- ActionContext.setContext(null);
- }
- }
- 在destroy()接口裏主要實現了銷燬Dispatcher和上下文的功能,示例代碼以下:
- public void destroy() {
- //若是Dispatcher爲空,則正常結束
- if (dispatcher == null) {
- log.warn("something is seriously wrong, Dispatcher is not initialized (null) ");
- } else {
- try {
- //銷燬Dispatcher
- dispatcher.cleanup();
- } finally {
- ActionContext.setContext(null);
- }
- }
- }
在doFilter()接口裏主要實現了建立Dispatcher和設置默認包的功能,示例代碼以下:
- public void doFilter(ServletRequest req, S ervletResponse res, FilterChain chain) throws
- IOException, ServletException {
- //獲取用戶請求的request
- HttpServletRequest request = (HttpServletRequest) req;
- HttpServletResponse response = (HttpServletResponse) res;
- ServletContext servletContext = getServletContext();
- //加上時間戳
- String timerKey = "FilterDispatcher_doFilter: ";
- try {
- //設定上下文或棧
- ValueStack stack = dispatcher.getContainer(). getInstance(ValueStackFactory.class).
- createValueStack();
- ActionContext ctx = new ActionContext(stack.getContext());
- ActionContext.setContext(ctx);
- //從新封裝request,記錄使用的語言、編碼方式、是不是上傳文件等
- UtilTimerStack.push(timerKey);
- request = prepareDispatcherAndWrapRequest(request, response);
- //獲取ActionMapping
- ActionMapping mapping;
- try {
- mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
- } catch (Exception ex) {
- //若是沒有找到合適的ActionMapping,則拋出異常
- dispatcher.sendError(request, response, servletContext, HttpServletResponse.
- SC_INTERNAL_SERVER_ERROR, ex);
- return;
- }
- //若是沒有配置ActionMapping,則判斷是否爲靜態資源
- if (mapping == null) {
- //獲取訪問請求的路徑
- String resourcePath = RequestUtils.getServletPath(request);
- if ("".equals(resourcePath) && null != request.getPathInfo()) {
- resourcePath = request.getPathInfo();
- }
- //判斷是否爲靜態資源
- if (staticResourceLoader.canHandle(resourcePath)) {
- staticResourceLoader.findStaticResource(resourcePath, request, response);
- } else {
- // 若是不是,則繼續執行下一個過濾器
- chain.doFilter(request, response);
- }
- return;
- }
- //在正常狀況下,調用serviceAction方法
- dispatcher.serviceAction(request, response, servletContext, mapping);
- //清空上下文和時間戳
- } finally {
- try {
- ActionContextCleanUp.cleanUp(req);
- } finally {
- UtilTimerStack.pop(timerKey);
- }
- }
- }