DispatcherServlet 请求处理源码分析

业务处理流程

  1. 请求匹配:通过 HandlerMapping 查找合适的处理器。
  2. 拦截器前置处理:执行所有的 HandlerInterceptorpreHandle 方法。
  3. 执行控制器方法:调用相应的控制器方法处理请求。
  4. 数据处理
    • 如果是视图返回,进行视图解析并渲染。
    • 如果是数据返回,使用 HttpMessageConverter 转换成合适的格式(如 JSON)。
  5. 拦截器后处理:执行所有 HandlerInterceptorpostHandle 方法。
  6. 视图渲染:将模型数据和视图渲染成最终的响应内容。
  7. 后置清理:执行所有 HandlerInterceptorafterCompletion 方法。
  8. 异常处理:如果有异常发生,进行异常处理。

doDispatch 源码

@SuppressWarnings("deprecation")
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;

    // 请求处理(这里后面详细分析,1、2、3)
    try { ... }
    catch (Exception ex) {
      // 如果发生异常,赋值给 dispatchException 变量
      dispatchException = ex;
    }
    catch (Throwable err) {
      // 如果发生错误,也赋值给 dispatchException
      dispatchException = new ServletException("Handler dispatch failed: " + err, err);
    }
    // 结果处理(后面详细分析,4、5、6)
    // 1,如果 dispatchException 不为空,说明请求处理发生了异常,使用异常解析器处理异常(如果异常解析器也发生异常呢?所以外层还有一层 try catch)
    // 2,如果 dispatchException 为空,说明请求处理正常,该返回视图或 json 都是这里做的
    // 3,也会执行拦截器的 afterCompletion 方法
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  }
  catch (Exception ex) {
    // 如果异常解析器也发生异常,也要执行拦截器的 afterCompletion 方法
    triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  }
  catch (Throwable err) {
    // 如果异常解析器也发生错误,也要执行拦截器的 afterCompletion 方法
    triggerAfterCompletion(processedRequest, response, mappedHandler,
        new ServletException("Handler processing failed: " + err, err));
  }
  finally {
    // 如果是异步请求的后续处理
    if (asyncManager.isConcurrentHandlingStarted()) {
      if (mappedHandler != null) {
        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
      }
    }
    else {
      // 如果是文件请求的后续处理
      if (multipartRequestParsed) {
        cleanupMultipart(processedRequest);
      }
    }
  }
}

通过上面源码分析可以知道

  1. 不管 handler 执行异常还是成功,拦截器的 afterCompletion 一定会执行(顺序是倒序执行)
  2. 内层 try catch 是处理 handler 执行异常,外层 try catch 是当异常解析器处理也发生异常的处理

寻找和执行 handler 源码

也就是内层的 try catch 不分,源码如下

// 1,检查是否是文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// 2,寻找处理器 Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
  noHandlerFound(processedRequest, response);
  return;
}

// 3,寻找 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// get head 请求用于获取资源,静态资源比如 css、图片等,动态资源比如 jsp、freemarket、servlet 等
// 当资源没有被修改并且缓存未失效就返回缓存
// 前后分离后这个缓存就没啥意义了
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
  long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    return;
  }
}

// 执行拦截器,如果不放行,请求处理结束,不会执行 handler
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  return;
}

// 真正执行 handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);

检查是否是文件上传请求

// org.springframework.web.servlet.DispatcherServlet#checkMultipart
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
    // 文件解析器不为空并且 ContentType 为 multipart/form-data 打头
    if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
        // request 是否是 MultipartHttpServletRequest(如果不是会返回 null)
        if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
            if (DispatcherType.REQUEST.equals(request.getDispatcherType())) {
                logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
            }
        } else if (hasMultipartException(request)) {
            logger.debug("Multipart resolution previously failed for current request - " +
                    "skipping re-resolution for undisturbed error rendering");
        } else {
            try {
                // 使用文件解析器解析请求
                return this.multipartResolver.resolveMultipart(request);
            } catch (MultipartException ex) {
                if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
                    logger.debug("Multipart resolution failed for error dispatch", ex);
                    // Keep processing error dispatch with regular request handle below
                } else {
                    throw ex;
                }
            }
        }
    }
    // 文件解析器肯定不会空,内置好了的。如果 ContentType 为=不是以 multipart/form-data 打头,就返回原 request
    return request;
}

// org.springframework.web.multipart.support.StandardServletMultipartResolver#resolveMultipart
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
    // 成员变量 resolveLazily 默认值是 false
    return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}

// org.springframework.web.multipart.support.StandardMultipartHttpServletRequest#StandardMultipartHttpServletRequest(jakarta.servlet.http.HttpServletRequest, boolean)
public StandardMultipartHttpServletRequest(HttpServletRequest request, boolean lazyParsing) throws MultipartException {
  	// 调用到好几辈的父类构造,目的就是赋值,把 request 赋值给成员变量
    super(request);
    // StandardMultipartHttpServletRequest 的成员变量 lazyParsing 默认就是 false
    if (!lazyParsing) {
      	// 这里真正解析
        this.parseRequest(request);
    }
}

// org.springframework.web.multipart.support.StandardMultipartHttpServletRequest#parseRequest
private void parseRequest(HttpServletRequest request) {
    try {
        // Servlet 3.0 新引入的 API,当 Content-Type 为 multipart/form-data 时方便从 HTTP 请求中获取表单字段和文件
        Collection<Part> parts = request.getParts();
        this.multipartParameterNames = new LinkedHashSet(parts.size());
        MultiValueMap<String, MultipartFile> files = new LinkedMultiValueMap(parts.size());
				// Part 是代表请求中的每一部分的对象。每个 Part 对象可以包含上传的文件或普通的表单字段
        for (Part part : parts) {
            String headerValue = part.getHeader("Content-Disposition");
            ContentDisposition disposition = ContentDisposition.parse(headerValue);
            String filename = disposition.getFilename();
            if (filename != null) {
                files.add(part.getName(), new StandardMultipartFile(part, filename));
            } else {
                this.multipartParameterNames.add(part.getName());
            }
        }
        // 就不贴源码了,源码就是下面这行注释,这个方法就是把 parts 解析后的 map 赋值给 multipartFiles 变量
        // this.multipartFiles = new LinkedMultiValueMap(Collections.unmodifiableMap(multipartFiles));
        this.setMultipartFiles(files);
    } catch (Throwable ex) {
        this.handleParseFailure(ex);
    }
}

寻找 Handler

// org.springframework.web.servlet.DispatcherServlet#getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  // MVC 启动时会维护好 handlerMappings
  // 默认有 RequestMappingHandlerMapping(处理@RequestMapping注解实现的 handler)、RouterFunctionmapping 等
  if (this.handlerMappings != null) {
    // 遍历所有的 处理器映射器 (处理器映射器维护了 url 和 handler,根据 url 就能找到 handler)
    for (HandlerMapping mapping : this.handlerMappings) {
      // 得到的是 处理器执行链(处理器+拦截器)
      HandlerExecutionChain handler = mapping.getHandler(request);
      if (handler != null) {
        return handler;
      }
    }
  }
  return null;
}

// org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  // 获取 handler(RequestMappingHandlerMapping 的 mappingRegistry 的 registry 中维护了所有 url 和 handler)
  // 这个方法内部还是有点逻辑,打个断点看下看下处理器映射器的各个属性就会比较清晰了
  Object handler = getHandlerInternal(request);
  if (handler == null) {
    handler = getDefaultHandler();
  }
  if (handler == null) {
    return null;
  }
  // 获取到的 handler 是否是字符串,如果是字符串就找对应的 bean 作为 handler
  if (handler instanceof String handlerName) {
    handler = obtainApplicationContext().getBean(handlerName);
  }

  // 请求缓存(把请求url写到request属性中,后续再处理就不用计算url了,直接可以从request中拿到)
  if (!ServletRequestPathUtils.hasCachedPath(request)) {
    initLookupPath(request);
  }

  // 这个方法比较简单,就是取出所有拦截器加上 handler 组合成 HandlerExecutionChain(这里就会用到上面写到request的url)
  HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

  if (logger.isTraceEnabled()) {
    logger.trace("Mapped to " + handler);
  }
  else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
    logger.debug("Mapped to " + executionChain.getHandler());
  }

  // 跨域处理
  if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
    CorsConfiguration config = getCorsConfiguration(handler, request);
    if (getCorsConfigurationSource() != null) {
      CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
      config = (globalConfig != null ? globalConfig.combine(config) : config);
    }
    if (config != null) {
      config.validateAllowCredentials();
    }
    executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
  }
	// 返回处理器执行链
  return executionChain;
}

寻找 HandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  // 通处理器映射器一致,处理器适配器也是mvc启动就维护好了,也有好几种类型,RequestMappingHandlerAdapter 处理 @RequestMapping 注解实现的 handler
  if (this.handlerAdapters != null) {
    for (HandlerAdapter adapter : this.handlerAdapters) {
      // 每个适配器通过 supports 决定支持处理哪种 handler
      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");
}

// 实现 jakarta.servlet.Servlet 接口的 handler 对应的适配器
public boolean supports(Object handler) {
  return (handler instanceof Servlet);
}

// 实现 org.springframework.web.servlet.mvc.Controller 接口的 handler 对应的适配器
public boolean supports(Object handler) {
  return (handler instanceof Controller);
}

// @RequestMapping 实现的 handler 对应的适配器(会被封装为 HandlerMethod 对象)
public final boolean supports(Object handler) {
  return (handler instanceof HandlerMethod handlerMethod && supportsInternal(handlerMethod));
}

执行 Handler

// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
    HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  
	// 对 HttpServletRequest 和 HttpServletResponse 包装(ServletWebRequest 类里面有一些方便操作请求的方法)
  ServletWebRequest webRequest = new ServletWebRequest(request, response);
  // 获取 handlerMethod 绑定数据的 WebDataBinder(作用是把 http 请求数据转换为 java 对象)
  WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
  // 同上面,获取 ModelFactory。负责处理请求时的模型对象初始化
  ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

  // 包装 handlerMethod。handlerMethod 是 handler 的描述对象,ServletInvocableHandlerMethod 是 handler 对应的执行对象
  ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
  
  // 设置参数处理器
  if (this.argumentResolvers != null) {
    invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  }
  // 设置返回值处理器
  if (this.returnValueHandlers != null) {
    invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  }
  // 设置数据绑定器工厂(方法入口刚得到的)
  invocableMethod.setDataBinderFactory(binderFactory);
  // 设置 parameterNameDiscoverer,用于在执行方法时提取方法参数的名称
  invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

  // 创建 ModelAndViewContainer 对象,负责存储控制器方法的返回值、模型数据和视图信息。这个容器会被用来存储后续的所有数据,最终用于生成响应
  ModelAndViewContainer mavContainer = new ModelAndViewContainer();
  mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
  modelFactory.initModel(webRequest, mavContainer, invocableMethod);
  mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

  // 创建一个 AsyncWebRequest,用于支持异步请求的处理(忽略)
  AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
  asyncWebRequest.setTimeout(this.asyncRequestTimeout);

  // 获取 WebAsyncManager,它是 Spring MVC 中管理异步请求的核心组件(忽略)
  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);
  }
  
	// 执行(这个方法会解析参数,反射执行 Controller 的方法,拿到结果后再处理响应)
  invocableMethod.invokeAndHandle(webRequest, mavContainer);
  
  // 检查异步处理是否已开始(忽略)
  if (asyncManager.isConcurrentHandlingStarted()) {
    return null;
  }

  // 如果异步处理没有启动,最终返回 ModelAndView。通过调用 getModelAndView,将控制器的返回结果和模型数据构造为一个 ModelAndView 对象,准备返回给客户端
  return getModelAndView(mavContainer, modelFactory, webRequest);
}

具体怎么执行执行

// org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
    Object... providedArgs) throws Exception {
	// 处理入参、反射调用 controller 方法
  Object returnValue = 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 {
    // 处理返回值
    this.returnValueHandlers.handleReturnValue(
        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  }
  catch (Exception ex) {
    if (logger.isTraceEnabled()) {
      logger.trace(formatErrorForReturnValue(returnValue), ex);
    }
    throw ex;
  }
}

// org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
    Object... providedArgs) throws Exception {
	// 解析入参,这个方法会选择参数解析器来解析参数,@PathVariable、@RequestParam、@RequestBody 对应不同的解析器(下面说怎么处理入参)
  Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
  if (logger.isTraceEnabled()) {
    logger.trace("Arguments: " + Arrays.toString(args));
  }
  // 有了参数,有了方法,剩下的就是朴实无华的反射调用方法了,最终调用到一个本地方法:jdk.internal.reflect.NativeMethodAccessorImpl#invoke0,这个方法一放行就到了 controller 的方法了 
  return doInvoke(args);
}
posted @   CyrusHuang  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示