Skip to content

Spring MVC 工作流程

Spring MVC 采用了前端控制器模式来设计整个请求处理流程,通过 DispatcherServlet 作为中央控制器来协调各个组件工作。下面详细介绍 Spring MVC 的工作流程。

整体流程图

Spring MVC 工作流程

详细工作步骤

  1. 客户端发送请求:浏览器或其他客户端向服务器发送 HTTP 请求

  2. 前端控制器接收请求:DispatcherServlet 作为前端控制器接收所有请求

  3. 处理器映射确定处理器

    • DispatcherServlet 咨询 HandlerMapping,确定由哪个 Controller 来处理请求
    • HandlerMapping 根据请求的 URL、HTTP 方法以及其他条件返回 HandlerExecutionChain
    • HandlerExecutionChain 包含 Handler 和所有应用于该请求的拦截器
  4. 处理器适配器调用控制器

    • DispatcherServlet 使用 HandlerAdapter 调用选中的 Handler(Controller)
    • HandlerAdapter 会根据 Controller 的类型适配不同的调用方式(如基于注解的控制器或实现特定接口的控制器)
    • 控制器执行业务逻辑,访问模型数据,准备视图数据
  5. 控制器处理请求

    • Controller 执行业务逻辑,可能调用 Service 层处理业务
    • Controller 可能访问数据库或其他资源
    • Controller 准备模型数据,选择视图名称或直接返回响应数据
    • 返回 ModelAndView 对象,包含视图名和模型数据
  6. 视图解析

    • 如果控制器返回逻辑视图名,DispatcherServlet 使用 ViewResolver 将逻辑视图名解析为实际的 View 对象
    • ViewResolver 可能使用不同的视图技术(JSP、Thymeleaf、FreeMarker 等)
    • 返回 View 对象给 DispatcherServlet
  7. 视图渲染

    • DispatcherServlet 将 Model 数据传递给 View
    • View 使用模型数据渲染最终的输出(如 HTML 页面)
  8. 返回响应

    • 渲染后的视图作为响应返回给客户端
    • 对于 REST API,可能直接返回 JSON/XML 数据而不经过视图渲染步骤

拦截器的工作流程

拦截器在 Spring MVC 流程中的执行点:

  1. preHandle:在 Controller 处理请求前执行

    • 返回 true 继续执行下一个拦截器或 Controller
    • 返回 false 终止流程,不再调用其他拦截器和 Controller
  2. postHandle:在 Controller 处理请求后、视图渲染前执行

    • 可以修改 ModelAndView
    • 如果 Controller 抛出异常,不会执行此方法
  3. afterCompletion:在整个请求处理完成后执行

    • 视图渲染后执行
    • 即使 Controller 抛出异常,也会执行此方法
    • 通常用于资源清理

关键组件与责任

组件责任
DispatcherServlet前端控制器,协调整个请求处理流程
HandlerMapping根据请求选择合适的 Controller
HandlerAdapter适配不同类型的 Controller 调用方式
Controller处理业务逻辑,准备模型数据
ModelAndView封装模型数据和视图信息
ViewResolver解析视图名为具体的 View 实现
View使用模型数据渲染最终输出

核心源码分析

DispatcherServlet 的核心处理逻辑在 doDispatch 方法中:

java
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 {
            // 1. 检查是否是文件上传请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 2. 确定处理请求的Handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 3. 获取处理器适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // 4. 处理Last-Modified头
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            
            // 5. 应用前置拦截器
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 6. 实际调用Handler,处理请求
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            // 7. 如果视图名为空,设置默认视图名
            applyDefaultViewName(processedRequest, mv);
            
            // 8. 应用后置拦截器
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        
        // 9. 处理结果,包括视图渲染
        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 {
        // 10. 清理请求相关资源
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }
        if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
        }
    }
}

Spring MVC 流程优化点

  1. 使用拦截器处理横切关注点:如日志、安全、国际化等
  2. 配置适当的视图解析器链:根据业务需求配置合适的视图技术
  3. 利用异步处理提高性能:对于长时间运行的请求使用异步处理
  4. 合理配置处理器映射:根据URL模式配置最高效的HandlerMapping
  5. 对静态资源使用专门的处理器:配置DefaultServletHttpRequestHandler处理静态资源
  6. 适当配置文件上传解析器:根据需求配置文件大小限制、临时目录等