JAVA源码剖析|SpringMVC请求流程处理源码剖析(我斑愿称你为最全)已完善最后总结


文章目录

  • 前言
        • 前端控制器DispatcherServlet的继承结构分析及请求处理传递流程(一图胜万语)
      • 1.根据请求url获取handler执行器链包含处理当前请求的处理器对象和处理器链 getHandler(processedRequest)方法;
      • 2.根据handler链中的handler处理器获取对应的HandlerAdapter处理器适配器getHandlerAdapter(mappedHandler.getHandler());
      • 3.依次执行handler链中拦截器数组中拦截器的preHandler方法,返回true继续执行,false直接return; mappedHandler.applyPreHandle(processedRequest, response)
      • 4.使用刚刚获取的HandlerAdapter处理器适配器执行handler逻辑,返回ModelAndView对象。mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      • 5.结果视图对象处理(如果未指定view逻辑视图名则根据请求路径给一个默认的逻辑视图名称)applyDefaultViewName(processedRequest, mv);
      • 6.依次执行handler链中拦截器数组中拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);
      • 7.数据模型model封装到请求域中并请求转发到真正的视图进行视图渲染processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
      • 8.依次执行handler链中拦截器数组中拦截器的afterCompletion方法??已经跳转渲染完毕之后,响应到浏览器之前执?(用来捕获视图渲染时发生的异常)triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
      • 总结SpringMVC处理请求的详细流程:

前言 SpringMVC是一个应用于表现层的经典框架,其中M代表模型(数据模型[pojo/vo/po]+业务模型)主要作用是充当C——>V的数据传递介质,V代表view视图(jps、html)负责请求域中M的展示,C代表Controller控制器(Servlet)主要作用是接收请求调用业务层进行业务处理,并将处理结果转发到V或者直接响应给浏览器。
SpringMVC请求处理流程较为宏观的描述
  1. 请求到达DispatcherServlet(前端控制器)后,DispatcherServlet调用HandlerMapping(处理器映射器)查询对应handler(处理器)
  2. HandlerMapping根据请求的url获取对应的handler给到DispatcherServlet
  3. DispatcherServlet将获取到的handler给到HandlerAdapter(处理器适配器)执行处理器处理请求业务
  4. handler执行后返回ModelAndView给DispatcherServlet
  5. DispatcherServlet请求视图解析器去解析view根据逻辑视图名拼接前后缀获取真正视图
  6. DispatcherServlet将数据模型model封装到请求域中并请求转发到真正的视图进行视图渲染
  7. 将渲染完成的视图响应给浏览器
    由上述流程可以看出DispatcherServlet是负责串联SpringMVC各大组件的核心类,同时也是第一个接触Request的类,我们的源码剖析之旅就从DispatcherServlet入手。
前端控制器DispatcherServlet的继承结构分析及请求处理传递流程(一图胜万语)
doDispatch源码:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; // 声明handler执行器链包含handler和拦截器数组 HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; // WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { // 声明ModelAndView ModelAndView mv = null; Exception dispatchException = null; try { // 检查是否文件上传请求如果是则返回MultipartHttpServletRequest不是则返回request原值 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. // 1.根据请求url获取handler执行器链包含处理当前请求的处理器对象和拦截器链 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { // 如果handler链为空,则返回404 noHandlerFound(processedRequest, response); return; }// Determine handler adapter for the current request. // 2.根据handler链中的handler处理器获取对应的处理器适配器(由于handler的格式不固定有可能是实现Controller接口的类, // 有可能是标记@RequestMapping的方法,所以不同的handler要对应不同适配器来执行handler业务逻辑) 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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 3.依次执行handler链中拦截器数组中拦截器的preHandler方法,返回true继续执行,false直接return if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; }// Actually invoke the handler. // 4.使用刚刚获取的HandlerAdapter处理器适配器执行handler逻辑,返回ModelAndView对象。 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 5.结果视图对象处理(如果未指定view逻辑视图名则根据请求路径给一个默认的逻辑视图名称) applyDefaultViewName(processedRequest, mv); // 6.依次执行handler链中拦截器数组中拦截器的postHandle方法 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); } // 7.数据模型model封装到请求域中并请求转发到真正的视图进行视图渲染 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { // 8.依次执行handler链中拦截器数组中拦截器的afterCompletion方法 //??已经跳转渲染完毕之后,响应到浏览器之前执?(用来捕获视图渲染时发生的异常) triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { // 同8 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); } } } }

提示:下面将按照doDispatch中的请求处理流程的8个主要流程逐一分析
1.根据请求url获取handler执行器链包含处理当前请求的处理器对象和处理器链 getHandler(processedRequest)方法;
HandlerExecutionChain处理器链包括handler和拦截器数组,处理器链类结构:
public class HandlerExecutionChain { private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class); // 处理器对象 private final Object handler; // 拦截器数组 @Nullable private HandlerInterceptor[] interceptors; @Nullable private List interceptorList; private int interceptorIndex = -1; //...省略若干方法}

DIspatcherServlet的getHandler(processedRequest)方法
DIspatcherServlet.class //处理器映射器集合 private List handlerMappings; protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }

JAVA源码剖析|SpringMVC请求流程处理源码剖析(我斑愿称你为最全)已完善最后总结
文章图片

HandlerMapping为处理器映射器,用于缓存和获取url对应的处理器和拦截器。
private List handlerMappings; 为处理器映射器集合,目前有两种实现1.BeanNameURLHandlerMapping用于保存在标签里配置的url与Handler和Interceptor之间的映射关系,目前基本不用了;2.RequestMappingHandlerMapping用于保存通过@RequestMapping注解配置的url与Handler和Interceptor之间的映射关系,目前主流。
下面进入AbstractHandlerMapping#getHandler
AbstractHandlerMapping.java public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 匹配handler Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } // 匹配拦截器数组,将获取到的拦截器数组+handler封装到HandlerExecutionChain处理器链对象中 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (logger.isTraceEnabled()) { logger.trace("Mapped to " + handler); } else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) { logger.debug("Mapped to " + executionChain.getHandler()); }if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); }return executionChain; }

2.根据handler链中的handler处理器获取对应的HandlerAdapter处理器适配器getHandlerAdapter(mappedHandler.getHandler());
由于handler的格式不固定有可能是实现Controller接口的类,有可能是标记@RequestMapping的方法,所以不同的handler要对应不同适配器来执行handler业务逻辑,HandlerAdapter可以理解为利用反射机制执行handler逻辑的反射工具类。
DIspatcherServlet.class // 处理器适配器集合 private List handlerAdapters; protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { 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"); }


根据handler在private List handlerAdapters; 处理器集合中选择合适的适配器
SpringMVC中自带了三个处理器适配器:
  1. HttpRequestHandlerAdapter,处理实现了HttpRequestHandler接口的handler
public boolean supports(Object handler) { return (handler instanceof HttpRequestHandler); }

  1. SimpleControllerHandlerAdapter,处理实现了Controller接口的handler
public boolean supports(Object handler) { return (handler instanceof Controller); }

  1. RequestMappingHandlerAdapter,处理被@RequestMapping注解标注的方法handler
public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }

3.依次执行handler链中拦截器数组中拦截器的preHandler方法,返回true继续执行,false直接return; mappedHandler.applyPreHandle(processedRequest, response)
此处会遍历拦截器数组中全部连接器,并且一次执行其preHandler方法,由此可见拦截器的preHandler在handler逻辑之前执行,可在拦截器的preHandler方法中进行权限验证等操作。
HandlerExecutionChain.class boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; // 调用拦截器的preHandler方法 if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }

4.使用刚刚获取的HandlerAdapter处理器适配器执行handler逻辑,返回ModelAndView对象。mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
a.进入ha.handle
AbstractHandlerMethodAdapter.java public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return handleInternal(request, response, (HandlerMethod) handler); }

b.进入handleInternal
RequestMappingHandlerAdapter.java protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ModelAndView mav; checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required. // 判断当前是否需要支持同一个session线性处理请求,保证session线程安全(可配置) if (this.synchronizeOnSession) { // 获取当前请求的session对象,如果尚未创建返回null。(如果getSession(true)是如尚未创建则会创建新session) HttpSession session = request.getSession(false); if (session != null) { // 根据session获取唯一key进行加锁 Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { // handler处理核心逻辑 mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No HttpSession available -> no mutex necessary // session=null时 // handler处理核心逻辑 mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No synchronization on session demanded at all... // session可以请求并行处理时 // handler处理核心逻辑 mav = invokeHandlerMethod(request, response, handlerMethod); }if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } }return mav; }

c.进入invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // 封装ModelAndView容器 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(result, !traceOn); return "Resume with async result [" + formatted + "]"; }); invocableMethod = invocableMethod.wrapConcurrentResult(result); } // handler核心处理逻辑 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 获取ModelAndView对象 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }

d.进入invokeAndHandle
ServletInvocableHandlerMethod.class public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // handler执行核心逻辑 Object returnValue = https://www.it610.com/article/invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; }mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null,"No return value handlers"); try { // 获取结果处理器,处理handler返回值,保存到ModelAndView容器中。 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }

e.进入invokeForRequest
InvocableHandlerMethod.class public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取handler1执行所需参数 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } // 反射调用handler方法,执行handler中的逻辑 return doInvoke(args); }

f.进入getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取当前handler方法的形参 MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } // 创建新数组,用于封装handler被调用时的实参(不同类型的形参获取方式不一样) Object[] args = new Object[parameters.length]; // 遍历形参 for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (!this.resolvers.supportsParameter(parameter)) { throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); } try { // 根据形参获取实参 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }

g.进入resolveArgument
HandlerMethodArgumentResolverComposite.class public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // 根据不同类型的参数获取不同的参数解析器。如:String的参数解析器AbstractNamedValueMethodArgumentResolver、Map的参数解析器MapMethodProcessor等 HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); if (resolver == null) { throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first."); } // 利用对应的参数解析器解析形参获取实参 return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }

此处以String的参数解析器AbstractNamedValueMethodArgumentResolver、Map的参数解析器MapMethodProcessor为例
h1.String的参数解析器AbstractNamedValueMethodArgumentResolver#resolveArgument里最终执行的是根据形参名称分别在请求头、请求Param中获取对应名称的参数
h2.Map的参数解析器MapMethodProcessor
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure"); // 直接返回ModelAndView容器中的Model作为实参,此处也可以解释:在方法中声明形参Map,Model,ModelMap并向里面填充的内容都会被写到请求域中 return mavContainer.getModel(); }

i.拿到handler执行的实参后回到第e步的doInvoke(args),反射调用handler方法
InvocableHandlerMethod.class protected Object doInvoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try { // 反射调用执行handler方法 return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } } }

j.到此handler方法以执行完毕,下面应处理handler返回值,保存到ModelAndView容器中,回到步骤d的this.returnValueHandlers.handleReturnValue()方法
HandlerMethodReturnValueHandlerComposite.class public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 根据不同结果类型获取不同的结果处理器如:String类型的结果处理器ViewNameMethodReturnValueHandler、ModelAndView类型的结果处理器ModelAndViewMethodReturnValueHandler HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } // 调用结果处理器完成handler返回值与ModelAndViewContainer的关系组装 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }

此处以String类型的结果处理器ViewNameMethodReturnValueHandler、ModelAndView类型的结果处理器ModelAndViewMethodReturnValueHandler为例子
k1.String类型的结果处理器ViewNameMethodReturnValueHandler#handleReturnValue
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 如果返回值是String时,将返回值作为逻辑视图保存到ModelAndViewContainer中的view里 if (returnValue instanceof CharSequence) { String viewName = returnValue.toString(); mavContainer.setViewName(viewName); // 返回值是否包含重定向关键字,如果包含设置RedirectModelScenario=true在视图渲染时会用到 if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } else if (returnValue != null) { // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); } }

k2.ModelAndView类型的结果处理器ModelAndViewMethodReturnValueHandler#handleReturnValue
当返回值是在handler中new ModelAndView时此处会与形参中的Map,Model等合并返回作为新的Model封装到容器中
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue =https://www.it610.com/article/= null) { mavContainer.setRequestHandled(true); return; }ModelAndView mav = (ModelAndView) returnValue; if (mav.isReference()) { String viewName = mav.getViewName(); mavContainer.setViewName(viewName); if (viewName != null && isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } else { View view = mav.getView(); mavContainer.setView(view); if (view instanceof SmartView && ((SmartView) view).isRedirectView()) { mavContainer.setRedirectModelScenario(true); } } mavContainer.setStatus(mav.getStatus()); // 当返回值是在handler中new ModelAndView时此处会与形参中的Map,Model等合并返回作为新的Model封装到容器中 mavContainer.addAllAttributes(mav.getModel()); }

l.到此handler的结果值以封装到ModelAndView容器ModelAndViewContainer中回到步骤c的 getModelAndView(mavContainer, modelFactory, webRequest); 方法中,获取ModeAndView对象并返回
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; }

5.结果视图对象处理(如果未指定view逻辑视图名则根据请求路径给一个默认的逻辑视图名称)applyDefaultViewName(processedRequest, mv);
进入applyDefaultViewName
DIspatcherServlet.class private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception { if (mv != null && !mv.hasView()) { // 在请求中根据url获取默认视图名称 String defaultViewName = getDefaultViewName(request); if (defaultViewName != null) { mv.setViewName(defaultViewName); } } }

进入getDefaultViewName
//默认视图名转换器组件 DefaultRequestToViewNameTranslator (SpringMVC9大组件之一) DIspatcherServlet.class private RequestToViewNameTranslator viewNameTranslator; protected String getDefaultViewName(HttpServletRequest request) throws Exception { // 如果初始化了默认视图名转换器组件则 return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null); }

进入getViewName
JAVA源码剖析|SpringMVC请求流程处理源码剖析(我斑愿称你为最全)已完善最后总结
文章图片

6.依次执行handler链中拦截器数组中拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);
此处会遍历拦截器数组中全部连接器,并且一次执行其postHandle方法,由此可见拦截器的postHandle在handler逻辑之后,视图渲染之前执行,可在拦截器的postHandle方法中对ModelAndView值进行修改。
进入applyPostHandle方法
HandlerExecutionChain.class public void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; // 循环调用拦截器的postHandler方法 interceptor.postHandle(request, response, this.handler, mv); } } }

7.数据模型model封装到请求域中并请求转发到真正的视图进行视图渲染processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
进入a.processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable 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.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } }if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; }if (mappedHandler != null) { //8.当页面渲染请求转发后无异常时也会依次执行handler链中拦截器数组中拦截器的afterCompletion方法 //afterCompletion方法在??已经跳转渲染完毕之后,响应到浏览器之前执?(用来捕获视图渲染时发生的异常) mappedHandler.triggerAfterCompletion(request, response, null); } }

b.进入render
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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null) { // We need to resolve the view name. // 根据逻辑视图名解析封装实际视图 view = resolveViewName(viewName, 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.isTraceEnabled()) { logger.trace("Rendering view [" + view + "] "); } try { if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } // 请求域数据封装,视图跳转(RedirectView重定向,AbstractUrlBasedView请求转发) view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "]", ex); } throw ex; } }

c.进入resolveViewName,View是个接口,根据不同的逻辑视图名称,会创建出不同的View实现
DIspatcherServlet.class //视图解析器SpringMVC的九大组件之一需在xml中配置InternalResourceViewResolver(extends UrlBasedViewResolver),主要作用设置视图前缀后缀 private List viewResolvers; protected View resolveViewName(String viewName, @Nullable Map model, Locale locale, HttpServletRequest request) throws Exception {if (this.viewResolvers != null) { // 遍历视图解析器,找到合适的视图解析器解析视图 for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }

d.进入resolveViewName
AbstractCachingViewResolver.class public View resolveViewName(String viewName, Locale locale) throws Exception { if (!isCache()) { return createView(viewName, locale); } else { // 默认开启视图缓存机制,视图渲染跳转过一次后会进行缓存 Object cacheKey = getCacheKey(viewName, locale); View view = this.viewAccessCache.get(cacheKey); if (view == null) { // 如果缓存中不存在该视图 synchronized (this.viewCreationCache) { // 防止并发不安全锁内再判断一边 view = this.viewCreationCache.get(cacheKey); if (view == null) { // Ask the subclass to create the View object. // 创建视图核心逻辑 view = createView(viewName, locale); if (view == null && this.cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null) { this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); } } } } else { if (logger.isTraceEnabled()) { logger.trace(formatKey(cacheKey) + "served from cache"); } } return (view != UNRESOLVED_VIEW ? view : null); } }

【JAVA源码剖析|SpringMVC请求流程处理源码剖析(我斑愿称你为最全)已完善最后总结】e.进入createView,根据逻辑视图名中不同的关键字获取不同类型的View实现如包含关键字"redirect:"创建RedirectView,包含关键字"forward"创建关键字InternalResourceView
protected View createView(String viewName, Locale locale) throws Exception { // If this resolver is not supposed to handle the given view, // return null to pass on to the next resolver in the chain. if (!canHandle(viewName, locale)) { return null; }// Check for special "redirect:" prefix. // 判断是否包含重定向关键字 if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); // 封装重定向视图 RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); String[] hosts = getRedirectHosts(); if (hosts != null) { view.setHosts(hosts); } // 将视图加载到Spring容器 return applyLifecycleMethods(REDIRECT_URL_PREFIX, view); }// Check for special "forward:" prefix. // 判断是否包含请求转发关键字 if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); // 封装请求转发资源视图InternalResourceView extends AbstractUrlBasedView InternalResourceView view = new InternalResourceView(forwardUrl); // 将视图加载到Spring容器 return applyLifecycleMethods(FORWARD_URL_PREFIX, view); }// Else fall back to superclass implementation: calling loadView. // 创建正常视图AbstractUrlBasedView(正常视图后面渲染流转也是走forward请求转发) return super.createView(viewName, locale); }

f.至此真正视图对象以获取,下面我们回到b步骤的view.render(mv.getModelInternal(), request, response);
请求域数据封装,视图跳转(RedirectView重定向,InternalResourceView请求转发)
AbstractView.class public void render(@Nullable Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) { logger.debug("View " + formatViewName() + ", model " + (model != null ? model : Collections.emptyMap()) + (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes)); } // 合并model Map mergedModel = createMergedOutputModel(model, request, response); // 准备响应设置参数 prepareResponse(request, response); // 请求域数据封装+请求转发 renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }

g1.进入RedirectView实现核心步骤RedirectView#renderMergedOutputModel
此处也解释了SpringMVC重定向请求数据传递的原理
JAVA源码剖析|SpringMVC请求流程处理源码剖析(我斑愿称你为最全)已完善最后总结
文章图片

RedirectView.class protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws IOException {String targetUrl = createTargetUrl(model, request); targetUrl = updateTargetUrl(targetUrl, model, request, response); // Save flash attributes //向session中添加Flash属性用于重定向传递参数 RequestContextUtils.saveOutputFlashMap(targetUrl, request, response); // Redirect // 完成重定向response.sendRedirect(encodedURL); sendRedirect(request, response, targetUrl, this.http10Compatible); }

g2.进入InternalResourceView实现核心步骤InternalResourceView#renderMergedOutputModel
protected void renderMergedOutputModel( Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {// Expose the model object as request attributes. // 将model中的数据封装到请求域里request.setAttribute(name, value); exposeModelAsRequestAttributes(model, request); // Expose helpers as request attributes, if any. exposeHelpers(request); // Determine the path for the request dispatcher. // 获取真实视图地址 String dispatcherPath = prepareForRendering(request, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). // 封装请求转发器javax.servlet.RequestDispatcher RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!"); }// If already included or response already committed, perform include, else forward. if (useInclude(request, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including [" + getUrl() + "]"); } // 注: 当前response是否已经设置了响应值,列入在某个拦截器或者Servlet中进行了处理,则会抛出异常,阻止当前跳转,响应之前设置的内容 rd.include(request, response); }else { // Note: The forwarded resource is supposed to determine the content type itself. if (logger.isDebugEnabled()) { logger.debug("Forwarding to [" + getUrl() + "]"); } // 请求转发 rd.forward(request, response); } }

注:至此视图的渲染和跳转已完成,等待当前请求的全部方法栈执行完毕后,浏览器即可看到调转效果,这里特别提一下回到a的mappedHandler.triggerAfterCompletion(request, response, null); 当视图渲染跳转过程中无异常时,最后也会执行一遍流程8,也就是遍历调用拦截器的afterCompletion方法,此时异常为null
8.依次执行handler链中拦截器数组中拦截器的afterCompletion方法??已经跳转渲染完毕之后,响应到浏览器之前执?(用来捕获视图渲染时发生的异常)triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
此处会遍历拦截器数组中全部连接器,并且一次执行其triggerAfterCompletion方法,由此可见拦截器的triggerAfterCompletion在视图渲染之后并且出现渲染异常时调用,可以在拦截器的triggerAfterCompletion方法中进行异常捕获。
总结SpringMVC处理请求的详细流程:
1.请求到达DispatcherServlet前端控制器,DispatcherServlet遍历处理器映射器HandlerMapping集合,根据请求的url匹配对应的处理器链HandlerExecutionChain包含一个Handler处理器和一个拦截器HandlerInterceptor[]数组。
2.DispatcherServlet遍历处理器适配器HandlerAdapter集合,根据处理器链中的Handler匹配对应的处理器适配器。
3.DispatcherServlet遍历处理器链中的拦截器数组,执行每个拦截器的preHandle方法(可在拦截器此方法中进行权限验证)
4.DispatcherServlet委派HandlerAdapter执行Handler业务方法,遍历handler的形参,根据不同的形参类型获取不同的HandlerMethodArgumentResolver参数解析器,调用参数解析器获取实参,获取实参后反射调用handler方法并保存方法returnValue返回值,根据返回值的类型获取对应的结果处理器,调用结果处理器将returnValue封装为ModelAndView返回DispatcherServlet.
5.检测ModelAndView中是否包含逻辑视图名称,如果逻辑视图名称为空则调用DefaultRequestToViewNameTranslator默认视图名称转换器 获取默认逻辑视图名称。
6.DispatcherServlet遍历处理器链中的拦截器数组,执行每个拦截器的postHandle方法
7.DIspatcherServlet遍历ViewResolver视图解析器数组获取对应的视图解析器,根据逻辑视图名称获取不同类型的View视图实现如(重定向视图RedirectView、请求转发资源视图InternalResourceView),获取到视图后将model数据写入请求域,然后进行请求转发或者重定向处理跳转到视图进行渲染。
8.当视图渲染完成或者渲染中出错时DispatcherServlet遍历处理器链中的拦截器数组,执行每个拦截器的afterCompletion方法
9.当前请求的全部方法栈执行完毕后Tomcat将渲染好的视图响应给浏览器。

    推荐阅读