专栏名称: java一日一条
主要是讲解编程语言java,并且每天都推送一条关于java编程语言的信息
目录
相关文章推荐
51好读  ›  专栏  ›  java一日一条

Spring MVC请求处理过程不是两张流程图就能讲清楚的

java一日一条  · 公众号  · Java  · 2020-12-07 18:34

正文

请到「今天看啥」查看全文


(isGet || "HEAD" . equals (method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ( new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return ;
}
}

// 执行拦截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return ;
}

// Actually invoke the handler.
// 利用HandlerAdapter来执行Handler里对应的处理方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return ;
}

// 如果没有设置视图,则应用默认的视图名
applyDefaultViewName(processedRequest, mv);
// 执行拦截器的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);
}
// 根据ModelAndView对象解析视图
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);
}
}
}
}


该方法就是 SpringMVC 处理请求的整体流程,其中涉及到几个重要的方法。

getHandler

该方法定义如下
/**
 * Return the HandlerExecutionChain for this request.
 * 为这个request返回一个HandlerExecutionChain
 */

@Nullable
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;
}


调试信息如下

根据调试信息可以看出, getHandler 方法主要是从 List handlerMappings 集合中遍历查找一个合适的处理器( Handler ),返回的结果是一个 HandlerExecutionChain 。然后再根据 HandlerExecutionChain 里携带的 Handler 去获取 HandlerAdapter

getHandlerAdapter

getHandlerAdapter 方法定义如下
/**
  * Return the HandlerAdapter for this handler object.
  * @param  handler the handler object to find an adapter for
  * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
  */

 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");
 }
调试信息如下


同样 getHandlerAdapter 方法主要是从 List handlerAdapters 集合中遍历查找一个合适的处理器适配器( HandlerAdapter ),返回的结果是一个 HandlerAdapter
可以看到此处 HandlerAdapter 真正的实现类是 RequestMappingHandlerAdapter

processDispatchResult

processDispatchResult 方法主要根据方法执行完成后封装的 ModelAndView ,转发到对应页面,定义如下
/**
 * Handle the result of handler selection and handler invocation, which is
 * either a ModelAndView or an Exception to be resolved to a ModelAndView.
 */

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) {
  // Exception (if any) is already handled..
  mappedHandler.triggerAfterCompletion(request, response, null);
 }
}

render

render 方法定义如下
/**
 * Render the given ModelAndView.
 *

This is the last stage in handling a request. It may involve resolving the view by name.
 * @param mv the ModelAndView to render
 * @param request current HTTP servlet request
 * @param response current HTTP servlet response
 * @throws ServletException if view is missing or cannot be resolved
 * @throws Exception if there's a problem rendering the view
 */


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对象
  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 + "] "






请到「今天看啥」查看全文