Spring MVC 底层工作流程+源码分析

Spring MVC 将 DispatcherServlet 作为前端控制器,所有请求都先汇聚于此,再由它委派给其他组件协同处理。


Spring MVC 核心流程图

Spring MVC 核心工作流程(含源码关键调用点)

ViewResolver 视图解析
DispatcherServlet 核心调度

  1. 找处理器
  2. 返回 HandlerExecutionChain
  3. 找适配器
  4. 返回 HandlerAdapter
  5. 前置拦截
    若 false 则中断
    若 true 继续
    执行业务方法
    返回 ModelAndView 或直接响应
  6. 后置拦截
  7. 处理结果渲染
  8. 视图解析与渲染
  9. 最终响应
  10. 清理资源
    HTTP Request
    返回
    doDispatch 入口
    getHandler 遍历 HandlerMapping
    getHandlerAdapter 获取匹配的 HandlerAdapter
    applyPreHandle 执行拦截器 preHandle
    HandlerAdapter.handle 执行 Controller 方法
    applyPostHandle 执行拦截器 postHandle
    processDispatchResult 处理结果和异常
    render 视图渲染
    triggerAfterCompletion 拦截器 afterCompletion
    Controller / @RequestMapping 方法
    resolveViewName 逻辑名 → View 对象
    View.render 输出 HTML/JSON

流程详解(对照源码行号)

步骤 角色 / 关键代码位置 说明
1 DispatcherServlet.doDispatch() line 920+ 所有请求入口,开始调度。
2 getHandler() -> 遍历 handlerMappings 通过 URL 找到 HandlerExecutionChain(含 Handler + Interceptor 列表)。
3 getHandlerAdapter() 根据 Handler 类型找到能执行它的适配器(如 RequestMappingHandlerAdapter)。
4 applyPreHandle() 依次执行每个拦截器的 preHandle 方法,若返回 false 则请求短路。
5 ha.handle() 适配器调用实际 Controller 方法(通过反射),并封装返回值为 ModelAndView
6 applyPostHandle() 执行拦截器的 postHandle 方法(在 Controller 之后、视图渲染之前)。
7 processDispatchResult() 统一处理 ModelAndView 或异常。
8 render() -> ViewResolver.resolveViewName() 根据逻辑视图名(如 "userList")解析出 View(如 InternalResourceView)。
9 View.render() 将模型数据与视图合并(如 JSP 渲染),输出到 HttpResponse
10 triggerAfterCompletion() 执行拦截器的 afterCompletion 方法(无论是否异常,最终清理)。

图中使用了子图 DispatcherServletViewResolver,并用不同颜色区分组件类型,流程箭头清晰标注了步骤序号,方便和源码对应。


精简版总结(一句话 + 一张表)

DispatcherServlet 接收请求 → HandlerMapping 定位 → HandlerAdapter 执行 → 拦截器干预 → 返回 ModelAndView → ViewResolver 渲染 → 输出响应

阶段 组件 源码方法
接收请求 DispatcherServlet doDispatch()
定位处理器 HandlerMapping getHandler()
执行处理器 HandlerAdapter ha.handle()
视图解析 ViewResolver resolveViewName()
视图渲染 View render()
拦截器回调 Interceptor preHandle / postHandle / afterCompletion

组件分析

核心组件(五大关键角色)

组件 职责
DispatcherServlet 中央调度器,接收请求并分发给其他组件
HandlerMapping 根据请求 URL 找到能处理它的 Handler(即 @RequestMapping 方法)
HandlerAdapter 适配器:确保不同类型的 Handler 能以统一方式被调用执行
ViewResolver 根据逻辑视图名(如 "hello")解析出真正的 View 对象(如 hello.jsp
View 负责视图渲染,将 Model 数据填充到视图中

执行流程:源码逐步拆解

1. 请求入口:doDispatch(Request, Response)

DispatcherServletdoDispatch 是处理所有请求的核心调度方法:

java 复制代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) 
    throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    ModelAndView mv = null;
    
    // ... 上下文设置、异步处理等 ...
    
    try {
        // ✅ 1. 检查文件上传
        processedRequest = checkMultipart(request);
        
        // ✅ 2. 获取处理器执行链 (Handler + Interceptors)
        mappedHandler = getHandler(processedRequest);
        if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
        }
        
        // ✅ 3. 获取支持该 Handler 的适配器
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        
        // ✅ 4. 执行所有拦截器的 preHandle 方法
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;  // 如果某个拦截器返回 false,流程中断
        }
        
        // ✅ 5. 核心!调用 Handler 执行业务逻辑,返回 ModelAndView
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        
        // ✅ 6. 执行所有拦截器的 postHandle 方法
        mappedHandler.applyPostHandle(processedRequest, response, mv);
        
        // ✅ 7. 最终视图渲染与异常处理
        processDispatchResult(processedRequest, response, 
                               mappedHandler, mv, dispatchException);
        
    } catch (Exception ex) {
        // 统一异常处理
    }
}

2. 处理器映射:getHandler(Request)

以下代码展示了如何为请求找到匹配的处理器:

java 复制代码
protected HandlerExecutionChain getHandler(HttpServletRequest request) {
    for (HandlerMapping hm : this.handlerMappings) {
        HandlerExecutionChain handler = hm.getHandler(request);
        if (handler != null) {
            return handler; // 返回包含 Handler 和拦截器链的对象
        }
    }
    return null;
}

3. 获取适配器:getHandlerAdapter(Handler)

以下代码展示了如何获取适配器:

java 复制代码
protected HandlerAdapter getHandlerAdapter(Object handler) {
    for (HandlerAdapter ha : this.handlerAdapters) {
        if (ha.supports(handler)) {
            return ha;
        }
    }
    throw new ServletException("No adapter for handler...");
}

4. 业务执行:ha.handle(...) -> ModelAndView

适配器的 handle 方法内部会:

  • 解析请求参数与 @PathVariable
  • 执行数据验证与类型转换
  • 通过反射调用 Controller 的具体方法
  • 将返回值(数据、视图名)封装为 ModelAndView 对象

5. 最终响应:processDispatchResult(...)

processDispatchResult 方法会调用 ViewResolverModelAndView 中的逻辑视图名解析为物理视图(如 JSP),并执行渲染。

java 复制代码
private void processDispatchResult(HttpServletRequest request,
        HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv,
        Exception exception) throws Exception {
    
    // 统一异常处理 
    // ...
    
    if (mv != null) {
        // 调用 ViewResolver 解析逻辑视图名
        render(mv, request, response);
    }
    
    // 执行所有拦截器的 afterCompletion 方法
    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

一个请求进来,从前到后的核心处理链就完整走通了:DispatcherServletHandlerMapping 定位方法 → HandlerAdapter 适配执行 → 反射调用业务代码,返回 ModelAndViewViewResolverView 渲染响应 → 中间穿插着 Interceptor 的拦截逻辑。

DispatcherServlet 类比为公司的前台总机,所有访客(请求)先到这里。总机根据来意查看地图(HandlerMapping )找到对应部门,找到后安排行政助理(HandlerAdapter )对接,业务办完后秘书将结果返回前台,再由总机指定专员(ViewResolver )制作最终的回执文件(View)交给访客。

相关推荐
Hexian25802 小时前
SpringAI系列(基础概念&springai系列 API)
spring·ai
java1234_小锋2 小时前
SpringBoot为什么要禁止循环依赖?
java·数据库·spring boot
折哥的程序人生 · 物流技术专研2 小时前
《Java 100 天进阶之路》第17篇:Java常用包装类与自动装箱拆箱深入
java·开发语言·后端·面试
RH2312113 小时前
2026.5.12 Linux
java·linux·数据结构
小新同学^O^3 小时前
简单学习 --> WebSocket
java·websocket·网络协议·学习
敲代码的瓦龙4 小时前
Java?枚举!!!
java·开发语言
NiceCloud喜云4 小时前
IntelliJ IDEA 保姆级安装 + ClaudeAPI 配置教程
java·开发语言·前端·ide·chrome·docker·intellij-idea
孙6903424 小时前
swf 图片转 pdf
java·后端
用户4682557459134 小时前
Spring AI MCP 实战:tools/list 启动快照陷阱与完整解法
java