一个请求在Spring MVC 中是怎么流转的
💡 核心入口:DispatcherServlet
所有Spring MVC请求的入口都是DispatcherServlet。它本质上是一个Servlet,其service()方法(由父类FrameworkServlet实现)最终会导向其核心方法doDispatch()。这个方法就像一个指挥中心,调度其他组件来完成请求处理。
// FrameworkServlet.java
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
// ... doPost, doPut, doDelete等方法类似
// processRequest方法最终会调用到DispatcherServlet的doService()方法
// DispatcherServlet.java
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// ... 做一些准备工作和属性设置 ...
doDispatch(request, response); // 核心分发逻辑
}
🚦 请求全链路剖析:doDispatch() 源码逐段解析
下面的流程图清晰地展示了doDispatch内部的核心步骤,我将配合每个步骤的源码进行深入解读。
-
checkMultipart:处理文件上传
流程开始,会检查当前请求是否是一个multipart/form-data类型的文件上传请求。如果是,则通过配置的MultipartResolver将HttpServletRequest对象包装为MultipartHttpServletRequest,以便后续方便地获取上传的文件。 -
getHandler:定位处理器
接下来,系统需要找到“谁来处理这个请求”。getHandler(request)方法会遍历注册的HandlerMapping组件,找到能处理当前请求的处理器(Handler),并返回一个包含该处理器和其关联的HandlerInterceptor(拦截器)的执行链。// DispatcherServlet.java protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { // 遍历所有注册的处理器映射器 for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; // 返回第一个找到的处理器执行链 } } } return null; }最常用的
HandlerMapping是RequestMappingHandlerMapping,它在项目启动时,会扫描所有标注了@Controller和@RequestMapping的类和方法,将请求路径(和HTTP方法)与目标方法(封装为HandlerMethod对象)的映射关系保存起来。getHandler方法的核心逻辑就在AbstractHandlerMethodMapping.lookupHandlerMethod中,它会根据请求路径在内部的mappingRegistry中进行精准匹配。 -
getHandlerAdapter:查找适配器
找到处理器后,DispatcherServlet需要一种统一的方式来调用它,因为处理器的形式可能是多样的(如实现Controller接口的类,或是标注了@RequestMapping的方法)。getHandlerAdapter方法的作用就是遍历所有注册的HandlerAdapter,找到能“支持”当前处理器的那个适配器,并在后续操作中使用它。// DispatcherServlet.java protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { // 遍历所有注册的处理器适配器 for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { // 判断是否支持该处理器 return adapter; // 返回第一个找到的适配器 } } } throw new ServletException("No adapter for handler..."); }对于
@RequestMapping注解的方法,Spring MVC会为其选择RequestMappingHandlerAdapter。这个适配器是处理现代Spring MVC控制器(以@Controller和@RequestMapping为代表)的核心。 -
拦截器「前置处理」:
applyPreHandle
在真正调用处理器方法之前,applyPreHandle方法会按照顺序执行处理器执行链中所有拦截器的preHandle方法。如果任何一个拦截器的
preHandle方法返回false,整个请求链路将在此被切断,后续的处理器方法和视图渲染都不会执行。 -
ha.handle:执行处理器
这是核心的业务处理阶段。HandlerAdapter的handle方法会利用Java的反射机制调用真正的Controller方法。在这个过程中,HandlerAdapter还会负责处理诸多繁重的工作,例如:- 参数解析:将请求参数(Query String、Form Data、JSON等)绑定到方法参数上。
- 返回值处理:将方法返回的对象(如
ModelAndView、POJO、ResponseEntity等)转换为统一的ModelAndView对象。
// RequestMappingHandlerAdapter.java (精简逻辑) @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav = null; // ... // 最终会委托给 ServletInvocableHandlerMethod 来调用 Controller 方法 ServletInvocableHandlerMethod invocableMethod = ...; invocableMethod.invokeAndHandle(request, response, mavContainer); // ... return getModelAndView(...); } -
拦截器「后置处理」:
applyPostHandle
在处理器方法执行完毕、但视图尚未渲染之前,applyPostHandle方法会按逆序执行所有拦截器的postHandle方法。如果处理器方法执行过程中抛出了异常,
postHandle方法将不会被执行。 -
processDispatchResult:处理结果
这个方法负责处理执行结果,主要包含两个子任务:- 异常处理:如果处理器执行过程中抛出了异常,它会调用配置的
HandlerExceptionResolver组件来解析异常,生成一个包含错误视图的ModelAndView。 - 视图渲染:调用
render方法,渲染最终的响应结果。
// DispatcherServlet.java private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { // 1. 处理异常 if (exception != null) { // 调用 HandlerExceptionResolver 来解析异常,生成对应的 ModelAndView mv = processHandlerException(request, response, mappedHandler, exception); } // 2. 视图渲染 if (mv != null && !mv.wasCleared()) { render(mv, request, response); } // ... 清理和后续处理 } - 异常处理:如果处理器执行过程中抛出了异常,它会调用配置的
-
render:视图渲染
如果ModelAndView包含视图信息(非@ResponseBody),该方法会执行:- 解析视图:遍历所有
ViewResolver,调用其resolveViewName方法,将逻辑视图名(如"user/list")解析为一个具体的View对象(如InternalResourceView,对应/WEB-INF/jsp/userList.jsp)。 - 渲染输出:调用
View对象的render方法,将模型数据(Model)填充到视图中,生成最终的HTML(或其他格式)内容,并写入HttpServletResponse。
// DispatcherServlet.java protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // 解析视图名称 View view = null; if (mv.isReference()) { // 遍历 ViewResolver 来解析视图名称 view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); } // 渲染视图 view.render(mv.getModelInternal(), request, response); } - 解析视图:遍历所有
-
拦截器「完成处理」:
triggerAfterCompletion
无论请求是正常处理完成,还是中途发生了异常,triggerAfterCompletion方法都会在最后被调用,按逆序执行所有拦截器的afterCompletion方法,用于执行清理资源等收尾工作。
🔗 总览:请求流转全路径总结图
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)