DispatcherServlet原始碼流程分析
DispatcherServlet是Spring MVC的核心內容,理解它的具體服務流程對於中高階應用開發是不可缺少的,下面將通過對原始碼進行註釋來分析下DispatcherServlet的流程處理
-
doService
作為分發請求的方法,doService方法的作用和servlet中的doService作用類似,接收http請求,然後提供對應的服務
/** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } //快照處理,使用快照可以更快響應使用者請求 // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<String, Object>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. //web IOC容器設定 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); //國際化屬性設定 request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); //主體屬性設定 request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); //一樣是主題設定 request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); //FlashMap開發部分 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { //對部分屬性進行設定完後,開始做請求的分發 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } }
這個方法中,做了對快照的處理和部分屬性的設定,重要的是所跳轉到的doDispatch方法
-
doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { //設定模型檢視以及異常處理 ModelAndView mv = null; Exception dispatchException = null; try { //設定檔案上傳處理解析器,並對是否為檔案上傳請求進行分析 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); //獲得匹配的執行器,如果執行器為空,進行錯誤處理 mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } //找到對應的執行器-->HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //開始處理請求頭,即對GET或POST請求進行處理 String method = request.getMethod(); boolean isGet = "GET".equals(method); //GET處理 if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //執行攔截器前的方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //執行處理器,返回ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } //設定檢視名稱 applyDefaultViewName(processedRequest, mv); //執行攔截器後的方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //對請求結果做解析,如果是邏輯檢視,則解析名稱,否則不解析,最後渲染檢視 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } //都是對異常的處理方法 catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } //釋放資源 finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
Dispatch方法的主要流程是:
- 通過請求找到對應的處理鏈,包括攔截器和控制器
- 通過處理器找到對應的介面卡
- 執行攔截器的事前方法,如果返回false,則流程結束
- 通過介面卡執行處理器,返回模型和檢視
- 對檢視和模型進行處理,執行攔截器事後方法
- 進行檢視和模型的解析操作
-
getHandler
在Dispatch方法中,用到了處理器和攔截器,這也是Dispatch方法的核心,接下來就是獲得處理器的方法getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //遍歷HandlerMapping for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } //將獲得的HandlerMapping物件進行轉換HandlerExecutionChain物件 HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
HandlerMapping是SpringMVC啟動時初始化的處理器對映,這裡做的操作主要是轉換成HandlerExecutionChain物件,也就是攔截器鏈,成員屬性如下
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
//控制器物件
private final Object handler;
//攔截器陣列
private HandlerInterceptor[] interceptors;
//攔截器連結串列
private List<HandlerInterceptor> interceptorList;
//攔截器下標,在對攔截器進行註冊時起定位作用
private int interceptorIndex = -1;
......
}
在這個物件裡用到的成員屬性都是使用HandlerInterceptor宣告的,點進HandlerInterceptor,可以看到有一段對HandlerInterceptor的介紹
* <p>HandlerInterceptor is basically similar to a Servlet Filter, but in
* contrast to the latter it just allows custom pre-processing with the option
* of prohibiting the execution of the handler itself, and custom post-processing.
* Filters are more powerful, for example they allow for exchanging the request
* and response objects that are handed down the chain. Note that a filter
* gets configured in web.xml, a HandlerInterceptor in the application context.
翻譯過來就是:HandlerInterceptor基本上類似於Servlet過濾器,但與後者不同的是,它允許自定義預處理和自定義後處理,比過濾器更強大,例如,它們允許在鏈式處理中傳遞equest和response請求,過濾器是在web.xml中配置的,而攔截器是在application中定義的
這裡的自定義預處理和後處理也就是剛才在Dispatch方法中標註出來的操作
HandlerInterceptor有三個方法
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
分別對應攔截器處理前,處理時,處理後所用到的方法,這就是處理器handler中攔截器的內容
dispatch方法的流程中最後是對檢視進行解析,原始碼裡就是processDispatchResult方法對檢視路徑進行解析,對檢視型別進行判斷,比較簡單,就不粘出來了