springmvc的执行过程

95 阅读5分钟

SpringMVC 的执行过程核心是  “前端控制器(DispatcherServlet)统一调度,各组件分工协作” ,整体流程围绕 “请求接收→处理器匹配→业务执行→视图渲染→响应返回” 展开,以下是详细拆解(含核心组件作用和执行顺序):

一、核心组件铺垫(先明确角色,再看流程)

在理解流程前,先记住 5 个核心组件的职责:

  1. DispatcherServlet(前端控制器) :SpringMVC 的 “中央调度器”,统一接收请求、分发任务、整合响应,是流程的核心入口和出口。
  2. HandlerMapping(处理器映射器) :根据请求路径(URL)匹配对应的 处理器(Handler) (如 Controller 的方法),并返回 “处理器执行链”(Handler + 拦截器)。
  3. HandlerAdapter(处理器适配器) :适配不同类型的 Handler(如注解式 @RequestMapping、XML 配置的 Controller),提供统一的执行接口,避免 DispatcherServlet 直接依赖具体 Handler 实现。
  4. ViewResolver(视图解析器) :将 Handler 返回的 ModelAndView 中的逻辑视图名(如 "index")解析为具体的物理视图(如 /WEB-INF/views/index.jsp)。
  5. View(视图) :接收 Model 数据,渲染页面(如 JSP、Thymeleaf),最终生成响应内容。

二、完整执行流程(10 步拆解)

假设用户发送请求:http://localhost:8080/springmvc/user/list(查询用户列表),流程如下:

1. 客户端发送请求,Tomcat 接收并转发

  • 用户通过浏览器 / 客户端发送 HTTP 请求(GET/POST 等),请求被 Web 服务器(如 Tomcat)接收。
  • Tomcat 根据项目的 web.xml 配置(或 SpringBoot 自动配置),发现请求路径匹配 DispatcherServlet 的映射规则(如 / 或 /springmvc/*),将请求转发给 DispatcherServlet

2. DispatcherServlet 接收请求,触发流程

  • DispatcherServlet 作为前端控制器,不直接处理业务,而是启动 “调度流程”,首先需要找到 “能处理该请求的处理器(Handler)”。

3. DispatcherServlet 调用 HandlerMapping,匹配 Handler

  • DispatcherServlet 调用容器中的 HandlerMapping(默认是 RequestMappingHandlerMapping,处理注解式 @RequestMapping)。

  • HandlerMapping 根据请求路径(/user/list)、请求方法(GET)等信息,匹配对应的 Handler—— 即 Controller 中被 @RequestMapping("/user/list") 注解的方法(如 UserController.list())。

  • HandlerMapping 返回一个 HandlerExecutionChain(处理器执行链) ,包含两部分:

    • 目标 Handler:UserController.list() 方法;
    • 拦截器(Interceptor):项目中配置的全局拦截器或局部拦截器(如登录校验拦截器)。

4. DispatcherServlet 调用 HandlerAdapter,适配并执行 Handler

  • DispatcherServlet 拿到 HandlerExecutionChain 后,不直接调用 Handler(因为 Handler 可能是注解式、XML 配置式等,形式不统一),而是调用 HandlerAdapter(默认是 RequestMappingHandlerAdapter)。

  • HandlerAdapter 负责 “适配” Handler:

    • 解析请求参数(如路径参数、请求体、RequestParam 等),并注入到 Handler 方法的参数中(如 list(Integer page, String name));
    • 执行拦截器的 preHandle() 方法(拦截器前置处理,如校验登录状态,返回 true 则继续,false 则终止流程);
    • 调用 Handler 方法(UserController.list()),执行业务逻辑(如调用 Service 查询数据库,获取用户列表数据)。

5. Handler 执行业务逻辑,返回 ModelAndView

  • UserController.list() 方法执行业务逻辑(如调用 UserService.queryUsers()),查询到用户列表数据后,返回一个 ModelAndView 对象:

    • Model:存储业务数据(如 model.addAttribute("userList", userList)),本质是一个 Map 结构;
    • View:逻辑视图名(如 return "user/list",表示视图名为 user/list,不包含后缀和路径)。
  • 若 Handler 没有返回 ModelAndView(如 @ResponseBody 注解的接口),则直接返回数据(JSON/XML),后续流程跳过 “视图渲染” 步骤(直接返回响应)。

6. 执行拦截器的 postHandle () 方法(拦截器后置处理)

  • Handler 执行完成后,HandlerAdapter 触发拦截器的 postHandle() 方法(在视图渲染前执行)。
  • 可通过该方法修改 ModelAndView(如统一添加全局数据、修改视图名)。

7. DispatcherServlet 调用 ViewResolver,解析逻辑视图

  • DispatcherServlet 拿到 ModelAndView 后,调用 ViewResolver(视图解析器) (默认是 InternalResourceViewResolver,处理 JSP)。

  • ViewResolver 根据逻辑视图名(user/list)和配置的视图前缀 / 后缀(如前缀 /WEB-INF/views/、后缀 .jsp),解析为物理视图路径:

    • 逻辑视图名 user/list → 物理路径 /WEB-INF/views/user/list.jsp
  • ViewResolver 返回一个具体的 View 对象(如 JstlView,对应 JSP 视图)。

8. View 渲染视图,填充 Model 数据

  • DispatcherServlet 将 Model 中的数据(如 userList)传递给 View 对象。
  • View 渲染页面(如 JSP 解析 EL 表达式 ${userList},Thymeleaf 解析 ${userList}),生成 HTML 等响应内容。

9. 执行拦截器的 afterCompletion () 方法(拦截器最终处理)

  • 视图渲染完成后,触发拦截器的 afterCompletion() 方法(无论流程成功 / 失败都会执行)。
  • 可通过该方法释放资源(如关闭流、清理线程局部变量)。

10. DispatcherServlet 返回响应,流程结束

  • DispatcherServlet 将渲染后的响应内容(HTML/JSON 等)通过 Tomcat 返回给客户端,浏览器接收后展示页面或解析数据。

三、关键注意点(避坑 / 面试重点)

  1. 拦截器执行顺序

    • preHandle():按拦截器配置顺序执行(先配置先执行);
    • postHandle():按拦截器配置逆序执行(后配置先执行);
    • afterCompletion():按拦截器配置逆序执行(后配置先执行)。
  2. @ResponseBody 特殊处理

    • 若 Handler 方法加了 @ResponseBody(或 Controller 加 @RestController),HandlerAdapter 会将返回值(如 POJO)直接通过 HttpMessageConverter 转换为 JSON/XML,不返回 ModelAndView,跳过 “视图解析” 和 “视图渲染” 步骤,直接返回响应。
  3. 异常处理

    • 流程中若发生异常(如 Handler 执行报错),会被 HandlerExceptionResolver(异常解析器)捕获,返回异常视图或 JSON 响应(如 @ExceptionHandler 注解的方法)。
  4. 核心组件的可扩展性

    • 可自定义 HandlerMappingHandlerAdapterViewResolver 等组件(如自定义视图解析器支持 Freemarker),替换 SpringMVC 的默认实现。

四、流程总结(一句话记核心)

请求→DispatcherServlet→HandlerMapping(找 Handler)→HandlerAdapter(执行 Handler + 拦截器)→ModelAndView→ViewResolver(解析视图)→View(渲染)→响应,全程由前端控制器统一调度,组件解耦,流程清晰可扩展。