对于任何使用Spring Boot进行Web开发的开发者而言,深入理解Spring MVC的执行流程都是至关重要的。
这不仅有助于我们编写更清晰、更高效的代码,更是我们排查诡异问题、进行高级定制开发的知识基石。
今天,我们将一起深入Spring Boot应用的内核,揭开Spring MVC处理HTTP请求的神秘面纱。
一、核心设计:前端控制器模式
Spring MVC的核心架构基于前端控制器模式(Front Controller Pattern)。该模式的核心思想是:用一个中央控制器来统一接收所有请求,并将其分发给相应的处理组件 。
在Spring MVC中,这个中央控制器就是 DispatcherServlet
。它是由Spring Boot通过自动配置(WebMvcAutoConfiguration
)自动注册的,默认映射路径为 /
,这意味着它成为了你应用处理所有Web请求的单一入口 和总调度中心 。
整个流程可以概括为:请求 -> DispatcherServlet
-> 查找处理器 -> 执行处理器 -> 处理结果 -> 响应 。下面我们来分解这个过程的每一个细节。
二、详细执行流程“八步走”
假设用户发起了一个获取用户信息的请求:GET
http://localhost:8080/api/users/1
。
其处理流程如下图所示,你可以结合下文步骤来理解:
第1步:请求抵达 DispatcherServlet
所有HTTP请求首先都会被 DispatcherServlet
接收。它是整个流程的“大脑”,负责协调后续的所有工作。
第2步:HandlerMapping
寻找处理器
DispatcherServlet
本身不处理业务逻辑,它的首要任务是问询一个或多个 HandlerMapping
组件:“这个请求应该由谁来处理?”。
HandlerMapping
会根据请求的URL(如 /api/users/1
),在注册的所有控制器中查找匹配的@RequestMapping
方法。找到后,它会返回一个 HandlerExecutionChain
对象。这个对象不仅包含了目标处理器(即我们@Controller
中的方法),还包含了配置好的拦截器(HandlerInterceptor
) 列表。
第3步:执行拦截器(Interceptor)的 preHandle
在真正执行业务逻辑之前,DispatcherServlet
会按顺序执行 HandlerExecutionChain
中所有拦截器的 preHandle
方法。
拦截器在这里可以进行权限校验、日志记录、参数预处理等。如果某个拦截器认为请求不合法(如用户未登录),它的 preHandle
方法会返回 false
,从而直接中断流程,跳转到最后一步。
第4步:HandlerAdapter
适配并执行处理器
不同的处理器可能有不同的执行方式(例如普通的@Controller
和旧的Controller
接口)。DispatcherServlet
需要找到一个能“驾驭”当前处理器的 HandlerAdapter
。最常用的是 RequestMappingHandlerAdapter
。
HandlerAdapter
是真正的“执行指挥官”,它负责:
- 数据绑定:将请求参数、URL路径变量、Session属性等绑定到处理器方法的参数上。我们常用的
@RequestParam
、@PathVariable
、@RequestBody
等都是在这一步生效的。 - 数据验证:如果参数标注了
@Valid
或@Validated
,会在此触发校验框架。 - 调用方法:最终通过反射机制,调用我们的控制器方法(如
UserController.getUserById(id)
),并获取其返回值。
第5步:处理器处理业务并返回
我们的控制器方法开始执行业务逻辑(如调用Service层查询用户数据),然后返回一个结果。这个结果通常有两种形式:
- 视图名(String):例如返回
"userInfo"
,表示需要渲染一个视图。 - 数据对象(Object):例如返回一个
User
对象,这在@RestController
中非常常见。
第6步:处理返回结果
这是流程的分水岭,DispatcherServlet
会根据返回结果的类型选择不同的处理策略:
- 返回视图名?交给
ViewResolver
!
ViewResolver
(视图解析器)会将逻辑视图名(如"userInfo"
)解析为一个具体的View
对象(如对应/templates/userInfo.html
的ThymeleafView)。后续View
对象会负责将模型数据渲染到HTML模板中,生成最终页面。
- 返回对象?交给
HttpMessageConverter
!
如果方法或类上有@ResponseBody
注解(@RestController
默认包含),DispatcherServlet
会遍历配置的HttpMessageConverter
(消息转换器)列表,选择一个合适的转换器(如MappingJackson2HttpMessageConverter
),将返回的Java对象序列化为JSON、XML等格式,并直接写入HTTP响应体。
第7 & 8 步:拦截器收尾与响应返回
- 执行
postHandle
:控制器方法执行后(但在视图渲染前 ),拦截器链会按逆序执行postHandle
方法,允许对模型数据进行最后修改。 - 执行
afterCompletion
:在整个请求处理完成(无论成功或异常)后,拦截器链会执行afterCompletion
方法,用于进行资源清理工作(如关闭连接)。 - 最终,生成的响应(HTML页面或JSON数据)通过
DispatcherServlet
返回给客户端浏览器。
三、不可或缺的异常处理机制
上述流程是“理想路径”。如果任何步骤抛出异常,流程会立即中断,并被 DispatcherServlet
捕获。
此时,DispatcherServlet
会转而委托 HandlerExceptionResolver
组件链来处理异常。这是我们实现统一异常处理的基础:
ExceptionHandlerExceptionResolver
:支持我们使用@ControllerAdvice
和@ExceptionHandler
注解来全局处理异常。ResponseStatusExceptionResolver
:处理标注了@ResponseStatus
的异常。DefaultHandlerExceptionResolver
:处理Spring内置的一些标准异常(如405 Method Not Allowed)。
异常解析器会将异常转换为一个友好的错误响应(如一个JSON错误信息),从而替代正常的流程结果。
总结
Spring MVC的流程清晰而模块化,每个组件各司其职:
DispatcherServlet
是协调全局的大脑 。HandlerMapping
是负责寻路的地图 。HandlerAdapter
是真正干活的双手 。ViewResolver
&HttpMessageConverter
是包装成果的化妆师 。HandlerInterceptor
是流程上的安检员 。HandlerExceptionResolver
是兜底的消防员 。
Spring Boot的自动配置魔法让我们无需手动组装这些零件,但理解它们如何协同工作,无疑会让你从一个Spring Boot的使用者,蜕变成为一个真正的架构理解者。希望这篇剖析能帮助你更好地驾驭Spring Boot Web开发。