从源码分析SpringMVC核心处理流程

简介: 从源码分析SpringMVC核心处理流程

引言


之前我们都是从一些官方文档或者是博客中了解了springMVC的整个处理流程,并且在前面博客我们也自己动手模拟了一个简单的springMVC容器,那么今天我们就对照流程图从源码分析一下S pringMVC的核心处理流程。


一、SpringMVC处理流程图


20201127175228352.png


这张图已经非常清楚的画除了整个SpringMVC的处理流程,里面还写出了每个处理环节当中的类,当然如果没有 分析过源码,那么上面的图看起来会非常的乱。尤其是里面的一些核心类,所以如果想很愉快的欣赏上面的 流程图,就需要我们看过几遍源码。


二、DispatcherServlet 核心处理流程


DispatcherServlet  其实就是一个普通的servlet,所以当一个请求来到servlet的时候,肯定首先会进入service()方法,所以我们的入口方法肯定是service()方法:


进入DispatcherServlet方法:


public class DispatcherServlet extends FrameworkServlet


我们在DispatcherServlet方法中我们没有发现service方法,所以肯定在父类的FrameworkServlet类中

@Override
  protected void service(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
      processRequest(request, response);
    }
    else {
      super.service(request, response);
    }
  }


从上面代码中我们会发现它继续调用了父类的service方法,所以我们继续进入到HttpServlet类中,在这个类中会见到我们非常熟悉的代码,也就是处理我们常见的几种处理方法:GET  HEAD DELETE POST PUT等。

  protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }
        } 
。。。。。。。。。。。
}

这里我们分析Get请求,当我们进入到源码以后会发现,get方法比其他的方法复杂一点,这是因为在get 和 head 方法里面处理一个缓存,也就是这个 lastModified,这在我们前后端分离之前会用到,也就是提高get请求的性能,类似时间戳的作用。这个东西在现在的前后端分离的架构中不是很重要了。


下面我们就开始进入找到get请求的主要实现里面:

20201127183027853.png


这样我们进入到一个processRequest方法,在doservice() 方法之前都是完成一些属性赋值。doservice()就是我们的核心方法

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = buildLocaleContext(request);
        //赋值一些属性 RequestAttributes  非常熟悉哈
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
    initContextHolders(request, localeContext, requestAttributes);
    try {
            //核心方法
      doService(request, response);
    }
    catch (ServletException | IOException ex) {
      failureCause = ex;
      throw ex;
    }
    catch (Throwable ex) {
      failureCause = ex;
      throw new NestedServletException("Request processing failed", ex);
    }
    finally {
      resetContextHolders(request, previousLocaleContext, previousAttributes);
      if (requestAttributes != null) {
        requestAttributes.requestCompleted();
      }
      logResult(request, response, failureCause, asyncManager);
      publishRequestHandledEvent(request, response, startTime, failureCause);
    }
  }

进入doService()核心方法:

@Override
  protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);
    。。。。。。。。。。
    //省略的代码主要是往request对象中赋值属性
    try {
      //核心代码
      doDispatch(request, response);
    }
  }


三、doDispatch()核心方法


核心执行流程图:


20201201155826174.png


开始分析doDispatch()核心方法,这里面完成核心流程,先来总体分析一下里面的几个核心方法,我都已经添加了注释,其实就是我们自己手写框架的时候实现的几个步骤。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    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);
        // Determine handler for the current request.
        //获得处理器HandlerMapping,这里返回的不在单个的HandlerMapping,而是HandlerExecutionChain 处理器+拦截器链
        mappedHandler = getHandler(processedRequest);
        if (mappedHandler == null) {
          noHandlerFound(processedRequest, response);
          return;
        }
        // Determine handler adapter for the current request.
        //获得对应的 适配器
        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;
          }
        }
        //执行拦截器前
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
          return;
        }
        // Actually invoke the handler.
        //执行具体的处理器逻辑
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        if (asyncManager.isConcurrentHandlingStarted()) {
          return;
        }
        applyDefaultViewName(processedRequest, mv);
        //执行拦截器中方法
        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);
      }
      // 处理返回结果和视图
      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);
        }
      }
    }
  }


1) 首先我们进入到 mappedHandler = getHandler(processedRequest); 这个方法,也就是完成根据URI获得处理器映射器的流程:

//这个代码是不是非常的熟悉,和我们手写框架中的代码几乎一样
@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;
  }

2、mapping.getHandler(request);具体实现逻辑在模板类AbstractHandlerMapping 实现

@Override
  @Nullable
  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 (logger.isTraceEnabled()) {
      logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
      logger.debug("Mapped to " + executionChain.getHandler());
    }
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
      CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      config = (config != null ? config.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
  }

3、getHandlerExecutionChain(handler, request);

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    //获得HandlerExecutionChain对象,HandlerExecutionChain构造器方法合并interceptors到interceptorList
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
        (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    // 将adaptedInterceptors添加到chain中,并存入到initInterceptorList中
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
      if (interceptor instanceof MappedInterceptor) {
        MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
        if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
          chain.addInterceptor(mappedInterceptor.getInterceptor());
        }
      }
      else {
        chain.addInterceptor(interceptor);
      }
    }
    return chain;
  }

上面几个核心方法我们获得了处理器,下面我们需要根据 处理器获得对应的适配器。

4、getHandlerAdapter(mappedHandler.getHandler());获得适配器

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");
  }

上面的方法我们就会非常的熟悉,获得适配器的代码和我们自己手写的框架中的代码是一样的。

5、mappedHandler.applyPreHandle(processedRequest, response);执行拦截器前方法,在执行具体的处理逻辑之前执行

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];
        //执行拦截器前方法,
        if (!interceptor.preHandle(request, response, this.handler)) {
          //执行拦截器后方法,规范上有规定,拦截器后的方法必须执行一次
          triggerAfterCompletion(request, response, null);
          return false;
        }
        this.interceptorIndex = i;
      }
    }
    return true;
  }

6、mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 执行具体业务逻辑


7、处理以后逻辑

//渲染视图
applyDefaultViewName(processedRequest, mv);
//执行拦截中的方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
//处理返回值逻辑
rocessDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

四、小结


本文从源码分析了springmvc的执行流程,通过这次分析,对于整个执行流程有了更深入的了解, 重要的是培养我们阅读源码的习惯。


目录
相关文章
|
XML 前端开发 Java
源码分析系列教程(05) - 手写SpringMVC
源码分析系列教程(05) - 手写SpringMVC
37 0
|
21天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
30 1
|
22天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
25 1
|
19天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
21 0
|
XML 设计模式 JSON
图文源码分析Spring MVC请求映射原理、执行流程
图文源码分析Spring MVC请求映射原理、执行流程
255 0
图文源码分析Spring MVC请求映射原理、执行流程
|
存储 Java 应用服务中间件
SpringMVC源码分析 DispatcherServlet源码分析
SpringMVC源码分析 DispatcherServlet源码分析
SpringMVC源码分析 DispatcherServlet源码分析
|
设计模式 缓存 前端开发
web九大组件之---HandlerAdapter适配器模式实践源码分析【享学Spring MVC】
web九大组件之---HandlerAdapter适配器模式实践源码分析【享学Spring MVC】
web九大组件之---HandlerAdapter适配器模式实践源码分析【享学Spring MVC】
|
Web App开发 前端开发 Java
SpringMVC源码分析2:SpringMVC设计理念与DispatcherServlet
转自:https://my.oschina.net/lichhao/blog SpringMVC作为Struts2之后异军突起的一个表现层框架,正越来越流行,相信javaee的开发者们就算没使用过SpringMVC,也应该对其略有耳闻。