上一篇: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的源码分析