Spring MVC 执行原理

Spring MVC 执行原理

通过跟进源码,整理了一些spring mvc 的运行流程,及一些自认为重要的代码片段,以记录为主,顺便分享一下。

Spring MVC 流程简述

首先是Spring Mvc的执行流程图
image

主要步骤

FrameworkServlet继承了HttpServlet

http请求发送到FrameworkServlet的doService方法,实现类是DispatcherServlet

  1. http请求到调度器servlet--DispatcherServlet;
  2. DispatcherServlet收到请求调用HandlerMapping处理映射器;
  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  4. DispatcherServlet调用HandlerAdapter处理适配器;
  5. HandlerAdapter转发到具体的Controller方法;
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将结果转到DiapatcherServlet;
  8. DispatcherServlet将model转到ViewResolver视图解析器;
  9. ViewReslover解析后返回具体View;
  10. DispatcherServler响应用户

详情

有兴趣的,来看我啰嗦一会

首先看一下工作时间最长的DispatcherServlet,简单了解一下它的功能

DispatcherServlet类和继承关系
org.springframework.web.servlet.DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {..}
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {...}

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {...}

关系图如下
image

现在开始步入正题

1 http请求到DispatcherServlet的doService方法

/**
 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
 * for the actual dispatching.
 */
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {...}

这是spring mvc的入口,spring mvc公开此方法,用于之后的调度。

此方法的部分代码:

// Make framework objects available to handlers and view objects.
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());

if (this.flashMapManager != null) {
   FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
   if (inputFlashMap != null) {
      request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
   }
   request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
   request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}

此代码是补充一些数据,后续的程序需要用到的一些数据;

数据的结构如图所示:
image

接下来就是核心代码了

doDispatch(request, response);

doDisPatch的注释已经把流程讲清楚了

/**
 * Process the actual dispatching to the handler.
 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
 * to find the first that supports the handler class.
 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
 */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {...}

所有的HTTP 请求都将这样处理::程序获取HandlerMappings和HandlerAdapters的第一个实现对象

2 DispatcherServlet收到请求调用HandlerMapping处理映射器

这一步的目的是获取HandlerMethod,其中包含请求对应的Controller及目标方法的信息

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

getHandler方法实现:取第一个实现的对象

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
         ...
         HandlerExecutionChain handler = hm.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

实现类:

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {...}

实现方法:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   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);
   }

   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
   if (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }
   return executionChain;
}

具体获取MappingHandler的操作:

List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

lookupPath是请求的路径,根据url获取对应的RequestMapping

每一个url都有对应的RequestMappingInfo对象,如图:
image

接下来是获取handlerMethod

获取到RequestMappingInfo对象后,调用方法,拼装Match,会从RequestMappingInfo中解析到handler信息拼到match中,目的是获取到hradlerMethod;

addMatchingMappings(directPathMatches, matches, request);

image
在此可以获取到url对应的Controller和对应的方法;

之后将HandlerMethod返回出去,获取HandlerMethod是此方法执行的主要目的;

其中,url对应的mapping信息来自于项目配置的xml文件或代码中的Controller相关注解;

3 DispatcherServlet调用HandlerAdapter处理适配器

此次目的是先要获取到一个HandlerAdapter;

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

用获取到的handler信息,来获取HandlerAdapter,mappedHandler.getHandler()---就是之前获取的HandlerMathod;

方法实现:

/**
 * Return the HandlerAdapter for this handler object.
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   if (this.handlerAdapters != null) {
      for (HandlerAdapter ha : this.handlerAdapters) {
         if (ha.supports(handler)) {
            return ha;
         }
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

HandlerAdapter有以下几个实现类:

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {...}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean  {...}
class CompositeHandlerAdapter implements HandlerAdapter  {...}
public class HttpRequestHandlerAdapter implements HandlerAdapter  {...}
public class SimpleControllerHandlerAdapter implements HandlerAdapter  {...}
public class SimpleServletHandlerAdapter implements HandlerAdapter  {...}

这里的关键方法ha.supports(handler)的实现有点过分简陋了,来这里寻找HandlerAdapter对象,简直就是白给的。

public final boolean supports(Object handler) {
   return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
protected boolean supportsInternal(HandlerMethod handlerMethod) {
   return true;
}

这里获取的HandlerAdapter是RequestMappingHandlerAdapter。

4 HandlerAdapter转发到具体的Controller方法

HandlerAdapter的目的是获取业务处理的结果,并将其封装成统一的ModelAndView

ModelAndView mv = null;
.......
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这个就是调用Controller方法,并将处理结果转成ModelAndView;

方法实现:

protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;
   checkRequest(request);

   // Execute invokeHandlerMethod in synchronized block if required.
   if (this.synchronizeOnSession) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
         synchronized (mutex) {
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      }
      else {
         // No HttpSession available -> no mutex necessary
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   }
   else {
      // No synchronization on session demanded at all...
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }

   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
      }
      else {
         prepareResponse(response);
      }
   }

   return mav;
}

这里有用到synchronized 来控制一个session里的请求必须是串行的,也就是单个spring mvc节点下,一个用户的请求不允许并发;

这里的请求都转到了invokeHandlerMethod方法执行

mav = invokeHandlerMethod(request, response, handlerMethod);
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);

      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();
         if (logger.isDebugEnabled()) {
            logger.debug("Found concurrent result value [" + result + "]");
         }
         invocableMethod = invocableMethod.wrapConcurrentResult(result);
      }

      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }

      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}

核心动作就是这个,执行方法

ServletInvocableHandlerMethod invocableMethod = new ServletInvocableHandlerMethod(handlerMethod);
invocableMethod.invokeAndHandle(webRequest, mavContainer);

此方法最终动作也就是调用反射的invoke方法,执行Controller的调用

public class InvocableHandlerMethod extends HandlerMethod {
    protected Object doInvoke(Object... args) throws Exception {
       ReflectionUtils.makeAccessible(getBridgedMethod());
 
      return getBridgedMethod().invoke(getBean(), args);
      ...
    }
}

下一步就是到了Controller方法里,这是笔者自己写的Controller方法,经过一大波的折腾,就是为了执行这段代码。

@RequestMapping(path = "/bwhealth")
public String health() {
    return "SUCCESS";
}

5 Controller执行完成返回ModelAndView

将Controller结果转换成modelAndView的代码还是这个

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {

   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
   setResponseStatus(webRequest);

   if (returnValue == null) {
      if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
         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 {
      this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   catch (Exception ex) {
      throw ex;
   }
}

主要是一些空判断处理等逻辑,核心代码就这一句转发

this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

实现就是对ModelAndViewContainer对象的数据进行拼装,获得到ModelAndView

return getModelAndView(mavContainer, modelFactory, webRequest);
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<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
      HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
      if (request != null) {
         RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
      }
   }
   return mav;
}

6 将http结果响应出去

接下来就是将ModelAndView的数据,发送到请求端,只是通过以下代码执行

((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage);
....
public final void write(final T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
      throws IOException, HttpMessageNotWritableException {

   final HttpHeaders headers = outputMessage.getHeaders();
   addDefaultHeaders(headers, t, contentType);

   if (outputMessage instanceof StreamingHttpOutputMessage) {
      StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
      streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {
         @Override
         public OutputStream getBody() {
            return outputStream;
         }
         @Override
         public HttpHeaders getHeaders() {
            return headers;
         }
      }));
   }
   else {
      writeInternal(t, outputMessage);
      outputMessage.getBody().flush();
   }
}

到此,请求方就收到了接口的响应结果

当然至此,代码还有一段路要走,就不再跟了。

这就是一个http请求进入spring mvc到出去的一些步骤,当然,事无巨细,还有很多细节没有展现出来,有兴趣的就自己跟一下源码看看吧。这会让你感觉,这么高大上的框架,实现起来也是这么的接地气,只不过是对一些基本操作的封装罢了。

原文地址:https://www.cnblogs.com/chenglc/p/13042364.html