SpringMVC的核心就是DispatcherServlet,DispatcherServlet实质也是一个HttpServlet。DispatcherSevlet负责将请求分发,所有的请求都有经过它来统一分发。
大致看下SpringMVC请求处理的流程: 用户向服务器发送请求,请求会到DispatcherServlet,DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI),然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括一个Handler处理器对象、多个HandlerInterceptor拦截器对象),最后以HandlerExecutionChain对象的形式返回。 DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;根据返回的ModelAndView,选择一个适合的ViewResolver返回给DispatcherServlet;ViewResolver 结合Model和View,来渲染视图,最后将渲染结果返回给客户端。
DispatcherSevlet中最重要的是doService方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 //获取请求,设置一些request的参数,然后分发给doDispatch @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应用上下文**/ 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 inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } //Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除 request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); //FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 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); } } } }
doService方法对Request设置了一些全局属性,最终接下来的操作是在doDispatcher:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 /** *将Handler进行分发,handler会被handlerMapping有序的获得 *通过查询servlet安装的HandlerAdapters来获得HandlerAdapters来查找第一个支持handler的类 *所有的HTTP的方法都会被这个方法掌控。取决于HandlerAdapters 或者handlers 他们自己去决定哪些方法是可用 *@param request current HTTP request *@param response current HTTP response */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { /* 当前HTTP请求**/ 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); // getHandler中遍历HandlerMapping,获取对应的HandlerExecutionChain // HandlerExecutionChain,包含HandlerIntercrptor和HandlerMethod mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } //获得HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //获得HTTP请求方法 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; } } //如果有拦截器的话,会执行拦截器的preHandler方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //返回ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } //当view为空时,,根据request设置默认view applyDefaultViewName(processedRequest, mv); //执行拦截器的postHandle 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); } } } }
HandlerInterceptor拦截器 在doDispatcher方法中:
1 mappedHandler = getHandler(processedRequest);
1 2 3 4 5 6 7 8 9 10 11 12 13 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; }
遍历HandlerMapping,获取对应的HandlerExecutionChain,HandlerExecutionChain中有3个变量:
1 2 3 private final Object handler; // HandlerMethod private HandlerInterceptor[] interceptors; //所有的HandlerInterceptor的数组 private List<HandlerInterceptor> interceptorList; //所有的HandlerInterceptor的链表
在执行Controller的方法调用之前先执行:
1 2 3 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; }
HandlerExecutionChain#applyPreHandle即调用HandlerInterceptor# preHandler方法。在Controller的方法调用之后:
1 mappedHandler.applyPostHandle(processedRequest, response, mv);
HandlerExecutionChain#applyPostHandle即调用HandlerInterceptor# postHandle方法。最后
1 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
方法会调用:
1 mappedHandler.triggerAfterCompletion(request, response, null);
调用HandlerInterceptor#afterCompletion方法。 详细用法参考 https://blog.csdn.net/zero__007/article/details/80028720
HandlerExceptionResolver异常处理 在doDispatcher方法中会catch住Controller方法调用的异常,之后再处理:
1 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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); } } // … }
如果有exception,调用processHandlerException:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) { exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } if (exMv != null) { if (exMv.isEmpty()) { request.setAttribute(EXCEPTION_ATTRIBUTE, ex); return null; } // We might still need view name translation for a plain error model... if (!exMv.hasView()) { exMv.setViewName(getDefaultViewName(request)); } if (logger.isDebugEnabled()) { logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex); } WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } throw ex; }
SpringMVC启动加载时会将所有的异常处理HandlerExceptionResolver实现类存放到handlerExceptionResolvers中,当默认执行时,只要返回的exMv不为空就中止执行其他的异常处理实现类。 可以实现多个HandlerExceptionResolver的异常处理类,执行顺序由其order属性决定, order值越小,越是优先执行, 在执行到第一个返回不是null的ModelAndView的Resolver时,不再执行后续的尚未执行的Resolver的异常处理方法。
HandlerMethodArgumentResolver参数解析器 HandlerMethodArgumentResolver是用来为处理器解析参数的,主要用在HandlerMethod中,每个Resolver对应一种类型的参数,其实现类特别的多。HandlerMethodArgumentResolver的接口定义如下:
supportsParameter 用于判断是否支持对某种参数的解析
resolveArgument 将请求中的参数值解析为某种对象
参数的处理是在InvocableHandlerMethod类中,当执行具体的请求处理时执行invokeForRequest:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //获取执行Controller的函数的参数对象 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) + "' with arguments " + Arrays.toString(args)); } Object returnValue = doInvoke(args); if (logger.isTraceEnabled()) { logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) + "] returned [" + returnValue + "]"); } return returnValue; }
具体的参数解析器的选择和使用参数解析器去解析参数的实现都在getMethodArgumentValues中。SpringMVC在启动时会将所有的参数解析器放到HandlerMethodArgumentResolverComposite,然后从HandlerMethodArgumentResolverComposite参数解析器集合中选择一个支持对parameter解析的参数解析器,之后就使用支持参数解析的解析器进行参数解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //获取执行的具体函数的参数 MethodParameter[] parameters = getMethodParameters(); Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(parameter, getBean().getClass()); //获取参数值对象 args[i] = resolveProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } //首先判断是否有参数解析器支持参数parameter,采用职责链的设计模式 if (this.argumentResolvers.supportsParameter(parameter)) { try { //如果参数解析器支持解析参数parameter,那么解析参数成Controller的函数需要的格式 args[i] = this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory); continue; } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex); } throw ex; } } if (args[i] == null) { String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i); throw new IllegalStateException(msg); } } //返回参数值 return args; }
以上代码会将URL链接提交的参数值转换为对象值。
HandlerMethodReturnValueHandler返回值解析器 HandlerMethodReturnValueHandler是用于对Controller中函数执行的返回值进行处理操作的。接口HandlerMethodReturnValueHandler定义的抽象方法如下:
supportsReturnType用于判断是否支持对返回值的处理。
handleReturnValue实现对返回值的处理操作。
执行过程是在ServletInvocableHandlerMethod的invokeAndHandle中:
1 2 3 4 5 6 7 8 9 10 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取返回值 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); ....... //对返回值进行处理操作 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); ......... }
具体实现是在HandlerMethodReturnValueHandlerComposite中,HandlerMethodReturnValueHandlerComposite中包含了所有springMVC提供的返回值处理器。
1 2 3 4 5 6 7 8 9 10 public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { //选择可以处理返回值的处理器 HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } //处理返回值 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
1 2 3 4 5 6 7 8 9 10 11 12 private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null; }