0%

springmvc全流程

Spring MVC 全流程详解:从请求到响应的完整链路

Spring MVC 作为分层架构的 Web 框架,其核心价值在于通过前端控制器(DispatcherServlet) 统一调度所有组件,将 HTTP 请求转化为业务逻辑处理与响应生成的标准化流程。从 “请求接收→组件协作→响应返回” 三个阶段,拆解 Spring MVC 的全流程执行逻辑,并结合核心组件(如 HandlerMapping、HandlerAdapter、ViewResolver)的作用,让你彻底理解每一步的底层原理。

Spring MVC 核心组件回顾

在解析全流程前,先明确参与流程的核心组件及其职责,这是理解流程的基础:

组件名称 核心职责
DispatcherServlet 前端控制器,全流程的 “总指挥”:接收请求、调度其他组件、返回响应
HandlerMapping 处理器映射器:根据请求 URL 找到对应的 Handler(Controller 方法)及拦截器,封装为 HandlerExecutionChain
HandlerAdapter 处理器适配器:适配不同类型的 Handler,调用其业务逻辑(如反射调用 @RequestMapping 方法)
Handler(Controller) 业务处理器:执行具体的业务逻辑,返回 ModelAndView(模型数据 + 视图名)或直接返回 JSON
HandlerInterceptor 拦截器:在请求处理的不同阶段(preHandle/postHandle/afterCompletion)执行横切逻辑(如权限校验、日志记录)
ViewResolver 视图解析器:将逻辑视图名(如 “user/list”)解析为具体的 View 对象(如 JSP、FreeMarker 模板)
View 视图:渲染模型数据到视图模板,生成 HTML 响应(如 JSP 引擎解析 EL 表达式)
HandlerMethodArgumentResolver 参数解析器:将 HTTP 请求数据(URL 参数、请求体、请求头)绑定为 Controller 方法参数
HttpMessageConverter 消息转换器:处理请求体 / 响应体与 Java 对象的转换(如 JSON 与 User 对象互转)

Spring MVC 全流程拆解(11 个核心步骤)

以下流程以 “用户访问 http://localhost:8080/user/list 获取用户列表” 为例,结合组件协作详细解析每一步:

阶段 1:请求接收(客户端→DispatcherServlet)

步骤 1:客户端发送 HTTP 请求

用户通过浏览器 / Postman 发送 GET 请求 http://localhost:8080/user/list,请求经 Web 容器(如 Tomcat)接收后,根据 web.xmlDispatcherServlet 的映射规则(<url-pattern>/</url-pattern>),将请求转发给 DispatcherServlet

步骤 2:DispatcherServlet 初始化检查

DispatcherServlet 未初始化(首次请求),会触发其初始化流程:

  1. 调用 HttpServletinit() 方法,通过继承链(DispatcherServlet→FrameworkServlet→HttpServletBean)完成上下文创建;
  2. 初始化核心策略组件(HandlerMapping、HandlerAdapter、ViewResolver 等),默认从 DispatcherServlet.properties 加载实现类,或使用 mvc:annotation-driven 自动注册的组件。

阶段 2:请求调度(DispatcherServlet→组件协作)

步骤 3:DispatcherServlet 调用 HandlerMapping 查找 Handler

DispatcherServlet 调用 getHandler(request) 方法,遍历所有 HandlerMapping(如 RequestMappingHandlerMapping),根据请求 URL 匹配对应的 HandlerExecutionChain(包含 Handler 和拦截器):

  • 匹配逻辑RequestMappingHandlerMapping 解析 @Controller 类中 @RequestMapping("/user/list") 注解,找到对应的 HandlerMethod(封装 UserController.list() 方法);
  • 拦截器整合:将与当前 URL 匹配的拦截器(如 LoginInterceptor)加入 HandlerExecutionChain,形成 “拦截器 1→拦截器 2→Handler” 的执行链。

核心源码(DispatcherServlet):

1
2
3
4
5
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response); // 无匹配 Handler,返回 404
return;
}
步骤 4:DispatcherServlet 调用 HandlerAdapter 适配 Handler

DispatcherServlet 调用 getHandlerAdapter(handler) 方法,遍历所有 HandlerAdapter(如 RequestMappingHandlerAdapter),找到支持当前 HandlerMethod 类型的适配器:

  • 适配逻辑RequestMappingHandlerAdaptersupports() 方法判断 handler 是否为 HandlerMethod 类型,返回 true 表示支持;
  • 作用:解决 DispatcherServlet 无法直接调用不同类型 Handler 的问题(如 HandlerMethodController 接口),通过适配器统一调用逻辑。

核心源码:

1
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
步骤 5:执行拦截器 preHandle 方法(正序)

DispatcherServlet 调用 mappedHandler.applyPreHandle(request, response),按拦截器配置顺序执行 preHandle 方法:

  • 执行逻辑:若拦截器返回 true,继续执行下一个拦截器;若返回 false,触发已执行拦截器的 afterCompletion 方法(反序),并终止流程(如未登录拦截);
  • 典型场景:权限校验(如检查 Session 中是否有登录用户)、请求日志记录(记录请求 URL、IP)。

核心源码(HandlerExecutionChain):

1
2
3
4
5
6
7
8
9
10
11
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null); // 反序执行 afterCompletion
return false;
}
this.interceptorIndex = i; // 记录最后一个成功执行的拦截器索引
}
return true;
}
步骤 6:HandlerAdapter 调用 Handler 执行业务逻辑

HandlerAdapter 调用 handle(request, response, handler) 方法,通过反射执行 HandlerMethod 对应的 Controller 方法(UserController.list()),核心逻辑包括:

  1. 参数解析RequestMappingHandlerAdapter 调用 HandlerMethodArgumentResolver 解析方法参数(如 @RequestParam@ModelAttribute),将 HTTP 请求数据绑定为 Java 类型(如 Integer page = 1);
  2. 请求体转换:若方法参数标注 @RequestBody,调用 HttpMessageConverter(如 MappingJackson2HttpMessageConverter)将请求体 JSON 转为 Java 对象;
  3. 业务逻辑执行:反射调用 UserController.list() 方法,查询用户列表数据,返回 ModelAndView(如 new ModelAndView("user/list", "userList", userList))或 @ResponseBody 标注的 JSON 对象。

核心源码(RequestMappingHandlerAdapter):

1
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
步骤 7:执行拦截器 postHandle 方法(反序)

若 Handler 执行成功(无异常),DispatcherServlet 调用 mappedHandler.applyPostHandle(request, response, mv),按拦截器配置反序执行 postHandle 方法:

  • 典型场景:修改 ModelAndView 数据(如统一添加当前登录用户信息)、替换视图(如动态切换主题视图);
  • 注意:若 Handler 抛出异常,此步骤跳过,直接进入异常处理流程。

核心源码:

1
2
3
4
5
6
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}

阶段 3:响应生成(视图渲染 / 异常处理→客户端)

步骤 8:异常处理(若有异常)

若 Handler 或拦截器抛出异常,DispatcherServlet 调用 processHandlerException(request, response, mappedHandler, ex),遍历 HandlerExceptionResolver(如 ExceptionHandlerExceptionResolver)处理异常:

  1. 异常解析ExceptionHandlerExceptionResolver 查找 @ControllerAdvice 或 Controller 内的 @ExceptionHandler 方法,执行异常处理逻辑(如返回错误 JSON 或错误视图);
  2. 结果生成:若异常处理成功,生成错误 ModelAndView;若失败,直接抛出异常,由 Web 容器返回 500 错误页面。
步骤 9:视图渲染(若无异常且需视图)

若 Handler 返回 ModelAndView(非 @ResponseBody),DispatcherServlet 调用 render(mv, request, response) 完成视图渲染:

  1. 视图解析ViewResolver(如 InternalResourceViewResolver)将逻辑视图名(如 “user/list”)解析为物理视图路径(如 /WEB-INF/jsp/user/list.jsp),创建 View 对象(如 JstlView);
  2. 模型数据暴露:将 ModelAndView 中的模型数据(如 userList)存入 HttpServletRequest 域(request.setAttribute("userList", userList));
  3. 视图渲染View 对象调用 render() 方法,通过 Web 容器(如 Tomcat 的 JSP 引擎)解析视图模板,填充模型数据,生成 HTML 响应。

核心源码(DispatcherServlet):

1
render(mv, request, response);
步骤 10:执行拦截器 afterCompletion 方法(反序)

无论 Handler 执行成功或失败,DispatcherServlet 最终调用 mappedHandler.triggerAfterCompletion(request, response, ex),按拦截器配置反序执行 afterCompletion 方法:

  • 典型场景:释放资源(如关闭文件流、数据库连接)、记录请求处理耗时、清理 ThreadLocal 变量;
  • 注意:仅执行 “preHandle 成功返回 true” 的拦截器的 afterCompletion 方法。

核心源码:

1
2
3
4
5
6
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.afterCompletion(request, response, this.handler, ex);
}
}
步骤 11:DispatcherServlet 返回响应

视图渲染完成后,DispatcherServlet 将 HTML 响应(或 @ResponseBody 生成的 JSON 响应)通过 Web 容器返回给客户端,完成整个请求流程。

全流程示意图

为更直观理解,结合步骤绘制简化流程:

graph TD
    A[客户端发送 HTTP 请求] --> B[Web 容器转发给 DispatcherServlet]
    B --> C["DispatcherServlet 初始化(首次请求)"]
    C --> D[DispatcherServlet 调用 HandlerMapping 查找 HandlerExecutionChain]
    D --> E[DispatcherServlet 调用 HandlerAdapter 适配 Handler]
    E --> F["执行拦截器 preHandle(正序)"]
    F -- 拦截器返回 true --> G[HandlerAdapter 调用 Handler 执行业务逻辑]
    F -- 拦截器返回 false --> H["执行已通过拦截器的 afterCompletion(反序),终止流程"]
    G --> I["执行拦截器 postHandle(反序)"]
    I --> J{是否有异常?}
    J -- 是 --> K[HandlerExceptionResolver 处理异常,生成错误响应]
    J -- 否 --> L{是否需要视图渲染?}
    L -- "是(ModelAndView)" --> M[ViewResolver 解析视图,渲染 HTML]
    L -- "否(@ResponseBody)" --> N[HttpMessageConverter 生成 JSON 响应]
    M/N --> O["执行拦截器 afterCompletion(反序)"]
    O --> P[DispatcherServlet 返回响应给客户端]

关键注意事项

  1. 组件优先级
    • 多个 HandlerMapping/HandlerAdapter 按 order 属性排序(值越小优先级越高);
    • 拦截器执行顺序:preHandle 正序,postHandle/afterCompletion 反序。
  2. 前后端分离场景差异
    • 若 Controller 方法标注 @ResponseBody,步骤 9(视图渲染)跳过,直接通过 HttpMessageConverter 生成 JSON 响应;
    • 异常处理返回 JSON 而非错误视图,需确保 @ExceptionHandler 方法标注 @ResponseBody 或使用 @RestControllerAdvice
  3. 性能优化点
    • 视图缓存:ViewResolver 开启缓存(cache=true),避免重复解析视图路径;
    • 组件初始化:load-on-startup=1 配置 DispatcherServlet,避免首次请求初始化延迟;
    • 静态资源处理:通过 mvc:resourcesdefault-servlet-handler 让 Web 容器直接处理静态资源,避免 DispatcherServlet 拦截。

总结

Spring MVC 全流程的核心是 “DispatcherServlet 统一调度 + 组件各司其职”,通过分层设计(请求接收→调度→业务执行→响应生成)实现解耦,让每个组件专注于单一职责:

  • 前端控制器(DispatcherServlet):总指挥,协调所有组件;
  • 映射器 / 适配器:连接请求与 Handler,解决适配问题;
  • 拦截器:横切关注点处理,不侵入业务代码;
  • 视图解析器:专注视图渲染,支持多种模板技术

欢迎关注我的其它发布渠道