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 容器返回给客户端,完成整个请求流程。

全流程示意图

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

拦截器返回 true
拦截器返回 false
是(ModelAndView)
否(@ResponseBody)
客户端发送 HTTP 请求
Web 容器转发给 DispatcherServlet
DispatcherServlet 初始化(首次请求)
DispatcherServlet 调用 HandlerMapping 查找 HandlerExecutionChain
DispatcherServlet 调用 HandlerAdapter 适配 Handler
执行拦截器 preHandle(正序)
HandlerAdapter 调用 Handler 执行业务逻辑
执行已通过拦截器的 afterCompletion(反序),终止流程
执行拦截器 postHandle(反序)
是否有异常?
HandlerExceptionResolver 处理异常,生成错误响应
是否需要视图渲染?
ViewResolver 解析视图,渲染 HTML
HttpMessageConverter 生成 JSON 响应
M/N
执行拦截器 afterCompletion(反序)
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,解决适配问题;
  • 拦截器:横切关注点处理,不侵入业务代码;
  • 视图解析器:专注视图渲染,支持多种模板技术

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

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10