上一篇:SpringMVC源碼分析-DispatcherServlet-init方法分析ios
DispatcherServlet的init已經將所須要的各類Resolver準備好,能夠說是萬事俱備只欠東風了,下面就看看它是如何接收請求,並將請求映射到Controller上的方法,而後將返回值格式化爲字符串或者使用視圖解析器完成解析的web
前半部分畫了從Tomcat最後一個閥門(Valve)如何一步步調用到DispatcherServlet的doService方法。json
後半部分畫了SpringMVC的處理流程,以下:後端
在DispatcherServlet中調用getHandler()獲得符合條件的HandlerMapping(如:RequestMappingRequestHandler-請求參數解析、綁定。。。在這裏面還會降將該請求適合的Interceptors與handler一塊兒封裝爲一個HandlerExecutionChain),接着根據獲得的HandlerMapping調用getHandlerAdpater()獲得符合條件的HandlerAdapter(如:RequestMappingHandlerAdapter-調用Controller中的方法,返回值格式化,肯定ModleAndView),在調用Controller以前執行攔截器的preHandle(),調用再接着調用HandlerAdapter的handle方法,在調用Contoller以後執行攔截器的postHandle()方法,最後調用processDispatchResult()根據MV執行轉發瀏覽器
DispatcherServlet-doDispatchapp
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);//文件上傳,轉換request爲mutipart request multipartRequestParsed = (processedRequest != request); // 決定當前請求使用的最優Handler,也就是說根據請求路徑去找到Controller中的某一個方法 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 根據mappedHanler中的HandlerMethod決定當前請求要使用的HandlerAdpater,好比RequestMappingHandlerAdapter 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)) { //getLastModified該方法都是返回-1,也不知道具體是幹什麼用的。感受像是判斷Mapping是否改變了,也許和熱加載有關係吧 long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //Invoke前處理--百度一大把SpringMVC請求流程中的講到的東西 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 真正invoke Handler對應的方法或者其餘對象,會完成參數綁定、方法調用、返回參數格式化等操做 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); //Invoke後處理 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } /** * 處理由前面選擇的處理器(mappedHandler)和處理器(HandlerAdapter)調用的結果:就是一個正常或者一個異常的MV * 而後再調用triggerAfterCompletion * 下面的兩個異常邏輯也須要調用triggerAfterCompletion * * */ processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { //異常-觸發「完成後」處理 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { //異常-觸發「完成後」處理 triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", 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); } } } }
DispatcherServlet.getHandle()前後端分離
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { /** * 循環全部的HandlerMappings,找到合適的HandlerMethod或者其餘類型的Handler * 將找到的Handler與攔截器一塊兒封裝一個HandlerExecutionChain * 下面看看RequestMappingHandlerMapping的getHandler方法 */ for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
RequestMappingHandlerMapping.getHandler(),最終會調用到它父類AbstractHandlerMethodMapping的getHandlerInternal()async
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); request.setAttribute(LOOKUP_PATH, lookupPath); this.mappingRegistry.acquireReadLock(); try { //從HandlerMappings當中找到一個最優匹配的Handler(MethodHandler) HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }
上面的代碼再調用AbstractHandlerMethodMapping的lookupHandlerMethod方法ide
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<>(); /** * mappingRegistry當中有一個urlLookup的Map,裏面存放的是全部以目錄形式訪問的路徑對應的RequestMappingInfo * 好比:/testweb/user/query * /testweb/user/save * 可是/testweb/user/query/{userName}這種就不行了,經過這個拆分可讓更多場景迅速找到惟一的RequestMappingInfo, * 減小循環遍歷全部的RequestMappingInfos,而後再Compare的耗時 */ List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } if (!matches.isEmpty()) { //MatchComparator定義了排序的規則,具體規則就不贅述了,百度一下或者看看RequestMappingInfo的CompareTo方法 Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); Match bestMatch = matches.get(0); if (matches.size() > 1) { if (logger.isTraceEnabled()) { logger.trace(matches.size() + " matching mappings: " + matches); } if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); String uri = request.getRequestURI(); throw new IllegalStateException( "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}"); } } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } }
DispathcerServlet.getHandlerAdapter()源碼分析
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { /** * 循環全部的handlerAdpaters,調用它們的supports方法找到匹配的HandlerAdapter * 以RequestMappingHandlerAdapter爲例看看它的supports方法 */ for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
上面的supports方法其實是RequestMappingHandlerAdapter父類AbstractHandlerMethodAdapter的supports
public final boolean supports(Object handler) { //supportsInternal()裏面竟然就是一個返回一個肯定的true,能夠想到,本身能夠擴展一個Adapter修改這個方法,更改MVC的默認匹配規則 return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }
能夠很清楚看到這個Adapter就是處理HandlerMethod這類型的Handler
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { /** * 循環執行攔截器的preHandle方法,若是返回值爲false,則還要倒序執行攔截的afterCompletion方法 */ for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }
這裏面有一個倒序執行攔截器的afterCompletion方法要注意
在這裏重點看底層被調用的
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { /** * 方法裏面首先解析參數,選擇對的HandlerMethodArgumentResolver,並完成參數值的綁定,好比: * RequestParamMethodArgumentResolver負責解析,完成參數綁定。沒有註解該Resolver一樣適用 * 由PathVariableMethodArgumentResolver負責解析,完成參數綁定 * 由RequestBodyMethodArgumentResolver負責解析,完成參數綁定 */ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); 。。。。省略部分代碼。。。。。 try { /** * 根據返回類型以及方法的註解判斷才用那個HandlerMethodReturnValueHandler來處理返回值 * * * * * */ this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
returnValueHandlers.handleReturnValue
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { //肯定應該使用的HandlerMethodReturnValueHandler HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } //對invoke返回的結果進行處理,好比進行json格式化 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
看看debug時handler是誰
再看看對返回結果轉換的核心代碼,能夠看到默認是有前面4個Converter的,最後一個Converter是我經過PostProcessor強行添加進去的
最終由MappingJacksonHttpMessageConverter完成對User對象的Json格式化轉換,並將轉換結果寫到了Response當中
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { /** * 循環執行攔截器的postHandle方法 */ for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } }
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; //異常MV處理 if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); //在這裏可使用自定義的ExceptionHandlerResolver對異常MV進行處理 mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } //渲染Handler返回的MV,渲染沒有深刻去看,由於如今流行先後端分離,幾乎都是返回的JSON串回去 if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } 。。。省略部分代碼。。。 if (mappedHandler != null) { // 最後執行afterCompletion方法 mappedHandler.triggerAfterCompletion(request, response, null); } }
最後只有執行完Tomcat的CoyoteAdapter.service中的以下兩行代碼瀏覽器纔會收到返回值
request.finishRequest(); response.finishResponse();
DispatcherServlet接收請求的處理流程涉及到幾個很是重要的擴展點,自定義HandlerMapping、自定義HandlerAdapter,一般SpringMVC是不建議開發者去修改最底層的內容的,可是SpringMVC容許且建議開發者能夠修改默認的HandlerMapping與HandlerAdpater當中屬性中的值,好比給Adapter添加argumentResolvers,initBinderArgumentResolvers,returnValueHandlers,MessageConverters等等
除了上面的內容,固然還有常常用到的一點就是Interceptor在HandlerAdapter.handle()以前的preHandle與以後postHandle,以及afterCompletion。須要注意preHandle的返回值爲false時會倒序調用攔截器中的afterCompletion方法
SpringMVC源碼複雜度和Spring比起來,前者仍是要輕鬆一些,總的來講在Tomcat啓動的時候調用DispatcherServlet.init方法經過Spring容器完成了全部默認組件與配置類的實例化與參數的加載,開發者能夠經過Spring提供的BeanPostProcessor修改這些默認類的實例化過程,修改它們的屬性值和行爲,而後在完成Dispatcher.init以後經過servlet規範調用到DispatcherServlet的service方法,經過以前已經實例化的組件與配置類實例共同做用完成了從請求到Controller的執行與返回瀏覽器的過程
接下來去開啓SpringBoot的源碼分析