• 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到出去的一些步骤,当然,事无巨细,还有很多细节没有展现出来,有兴趣的就自己跟一下源码看看吧。这会让你感觉,这么高大上的框架,实现起来也是这么的接地气,只不过是对一些基本操作的封装罢了。

  • 相关阅读:
    中国科学院2021年硕转博考试分析试题参考解答
    蒲和平大学生数学竞赛教程答案5.1.3
    清华大学2021年数学推荐免试试题参考解答
    蒲和平大学生数学竞赛教程答案4.1.1
    兰州大学历年数学分析高等代数考研试题答案
    复旦大学2021年数学英才实验班选拔考试试题参考解答pdf
    北京大学2021年基础学科招生考试数学试题
    南开大学2021年数学伯苓班/复旦大学2021年数学英才实验班选拔考试试题
    实变函数与泛函分析第05次课:至1.5.2(请点阅读全文进课堂)
    中国科学技术大学2021年新生入学考试试题
  • 原文地址:https://www.cnblogs.com/chenglc/p/13042364.html
Copyright © 2020-2023  润新知