DispatcherServlet提供Spring Web MVC的集中訪問點,並且負責職責的分派,並且與Spring IoC容器無縫集成,從而能夠得到Spring的全部好處。DispatcherServlet主要用做職責調度工做,自己主要用於控制流程,主要職責以下:java
一、文件上傳解析,若是請求類型是multipart將經過MultipartResolver進行文件上傳解析;web
二、經過HandlerMapping,將請求映射處處理器(返回一個HandlerExecutionChain,它包括一個處理器、多個HandlerInterceptor攔截器);設計模式
三、經過HandlerAdapter支持多種類型的處理器(HandlerExecutionChain中的處理器);app
四、經過ViewResolver解析邏輯視圖名到具體視圖實現;ssh
五、本地化解析;async
六、渲染具體的視圖等;post
七、若是執行過程當中遇到異常將交給HandlerExceptionResolver來解析。學習
看着上面的總結確定知道了大致上的處理過程,可是對於實際的邏輯實現確定是一頭霧水,DispatcherServlet的主要處理是在doDispatch()方法中實現的。看看具體的代碼實現:this
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); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); 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; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(request, 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); } } } }
首先看代碼:processedRequest = checkMultipart(request);就是爲了處理文件類型的請求,若是請求類型是multipart將其轉化經過MultipartResolver進行文件上傳解析;若是不是就返回原來的請求。spa
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) { logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " + "this typically results from an additional MultipartFilter in web.xml"); } else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) { logger.debug("Multipart resolution failed for current request before - " + "skipping re-resolution for undisturbed error rendering"); } else { return this.multipartResolver.resolveMultipart(request); } } // If not returned before: return original request. return request; }
首先判斷是否是MultipartHttpServletRequest請求,若是是就不須要再處理了,若是是這繼續判斷是否含有文件解析失敗異常,若是沒有最後纔會調用MultipartResolver接口實現類的resolveMultipart()方法來具體處理這個請求而且最後返回MultipartHttpServletRequest。固然了若是不是一個文件類型的請求就會直接的返回原始請求。
doDispatch()方法中的mappedHandler = getHandler(processedRequest);完成了HandlerExecutionChain(處理器運行鏈,由處理器和處理器攔截器組成)的尋找定位工做。看下如何具體獲取HandlerExecutionChain的過程:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
這個過程就和SpringMVC處理化的過程有關了,SpringMVC初始化中經過initHandlerMappings(ApplicationContext context)方法初始化了List<HandlerMapping> handlerMappings;也就是經過將全部配置的請求映射放到了這個handlerMappings。這個方法的處理過程簡單就是循環遍歷這個handlerMappings,若是找到了就返回具體的HandlerMapping 中的HandlerExecutionChain,不然就返回null.若是返回的處理器爲空,說明沒有可以處理這個請求的 HandlerMapping,那麼就會調用noHandlerFound(processedRequest, response)進行處理,看下noHandlerFound(processedRequest, response)具體的工做。
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception { if (pageNotFoundLogger.isWarnEnabled()) { pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) + "] in DispatcherServlet with name '" + getServletName() + "'"); } if (this.throwExceptionIfNoHandlerFound) { ServletServerHttpRequest sshr = new ServletServerHttpRequest(request); throw new NoHandlerFoundException( sshr.getMethod().name(), sshr.getServletRequest().getRequestURI(), sshr.getHeaders()); } else { response.sendError(HttpServletResponse.SC_NOT_FOUND); } }
設置HTTP響應狀態,而且拋出異常。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());決定了獲取請求對應的處理器適配器。看下具體的實現:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
和獲取請求的HandlerExecutionChain對象同樣,遍歷初始化就完成的handlerAdapters,有返回沒有則拋出異常。
對於請求方式是GET或者HEAD的,會判斷是否發生改變,若是沒有改變就直接返回,不然就繼續下去
方法ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;是使用給定的處理器來處理這個請求,而且返回一個ModelAndView 。以SimpleServletHandlerAdapter爲例,實際上是調用一個Servlet的Service方法來進行相應的業務邏輯的處理的。
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null; }
對上面處理後的視圖或者異常轉化成一個ModelAndView對象:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
若是有異常則將異常轉化成ModelAndView,若是視圖不爲空,則調用render(mv, request, response);進行視圖的解析渲染。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = this.localeResolver.resolveLocale(request); response.setLocale(locale); View view; if (mv.isReference()) { // We need to resolve the view name. view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + getServletName() + "'"); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'"); } try { view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'", ex); } throw ex; } }
首先獲取請求的本地化處理而且將其設置到response中,若是指定了視圖名字那麼DispatcherServlet就會調用相應的視圖解析器來進行解析,返回View對象
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; }
若是ModelAndView 沒有視圖引用說明,它已經含有了一個真實的View對象直接過去便可。若是獲取的View對象爲空則須要爆出異常。最後也是最重要的就是調用View對象的render方法( view.render(mv.getModelInternal(), request, response))進行視圖的渲染了。看具體實現是在View的實現抽象類中AbstractView中。
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Rendering view with name '" + this.beanName + "' with model " + model + " and static attributes " + this.staticAttributes); } Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }
簡單的說就是獲取數據而且填充,打完收工。
上面即是按照DispatcherServlet從接受到一個請求到請求徹底處理完成所經歷的一個過程,非常清晰明確。設計也很簡單。從設計到實現,能夠察覺設計模式的幾大原則和具體的設計都有涉及,從中也學到了不少東西,接着學習,加油。