📌 阅读前提示 :第 15 篇搭好了 MVC 的组织架构(九大组件)。本篇把镜头拉到「运行时」------每一次 HTTP 请求进来,
DispatcherServlet.doDispatch是如何调度这九个组件的。这是 MVC 源码里最核心、面试命中率最高的一篇,建议配合本篇配图逐行跟。
一、引子:所有请求都收敛到这一个方法
无论你写多少个 Controller,最终它们都通过一个统一的入口被调用------doDispatch。理解它,你就理解了 MVC 的「调度本质」:
找处理器(HandlerMapping)→ 选适配器(HandlerAdapter)→ 执行(拦截器 + 反射调用)→ 渲染(ViewResolver)→ 异常兜底。
二、doDispatch 主干源码
java
// DispatcherServlet.java
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// ① 文件上传请求预处理
processedRequest = checkMultipart(request);
// ② 找 Handler(遍历所有 HandlerMapping)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response); // 404
return;
}
// ③ 找 HandlerAdapter(遍历所有 HandlerAdapter)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ④ 处理 Last-Modified(GET 缓存)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return; // 任一 preHandle 返回 false → 中断
}
// ⑤ 真正执行 Handler(适配器内部反射调用 Controller 方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// ⑥ 视图名翻译(无显式视图名时用 RequestToViewNameTranslator)
applyDefaultViewName(processedRequest, mv);
// ⑦ 拦截器 postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// ⑧ 处理结果:渲染视图 或 处理异常
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} finally {
// ⑨ 清理文件上传资源
if (multipartRequestParsed) cleanupMultipart(processedRequest);
}
}
📌 关键顺序 :
preHandle→handle(Controller)→postHandle→processDispatchResult(渲染/异常)。注意postHandle在handle之后、但在视图渲染之前。
三、三个核心子方法
3.1 getHandler:遍历 HandlerMapping 找处理器
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;
}
💡 返回的不只是 Handler 方法 :而是
HandlerExecutionChain------它把「目标 Handler + 匹配的拦截器链」打包在一起。@RequestMapping由RequestMappingHandlerMapping处理。
3.2 getHandlerAdapter:按 supports 选适配器
java
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) return adapter; // HandlerAdapter.supports 判定
}
}
throw new ServletException("No adapter for handler [" + handler + "]");
}
常见适配器:RequestMappingHandlerAdapter(注解 Controller)、HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter(实现 Controller 接口的老式)。
3.3 processDispatchResult:渲染或异常
java
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
// 有异常 → 交给 HandlerExceptionResolver 解析
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception); // 异常解析器
errorView = (mv != null);
}
}
if (mv != null && !mv.wasCleared()) {
render(mv, request, response); // ★ 视图渲染
if (errorView) WebUtils.clearErrorRequestAttributes(request);
}
// 触发 afterCompletion(finally 语义)
if (mappedHandler != null) mappedHandler.triggerAfterCompletion(request, response, null);
}
四、doDispatch 主干流程图

五、常见误区
| 误区 | 正解 |
|---|---|
| HandlerMapping 直接调用 Controller | 不,它只返回 HandlerExecutionChain,执行交给 Adapter |
| postHandle 在 Controller 之后立即渲染前执行 | 是,但异常处理时 postHandle 不执行(异常在 handle 阶段抛出) |
| 拦截器一定有 afterCompletion | 只有 preHandle 返回 true 的拦截器,才会触发 afterCompletion |
| 404 也会走 processDispatchResult | 不,getHandler 返回 null 时直接 noHandlerFound 返回 |
| 视图渲染由 ViewResolver 完成 | ViewResolver 只「解析出 View 对象」,渲染由 View.render() 负责 |
🧪 面试题自测
- doDispatch 的完整执行顺序?
- getHandler 返回的是什么对象?为什么是「链」?
- HandlerAdapter 的 supports 起什么作用?
- 拦截器 preHandle / postHandle / afterCompletion 的触发时机与条件?
- 异常发生时,postHandle 还会执行吗?为什么?
- 404 和 500 在 doDispatch 里的处理路径有何不同?
🔧 Debug 小技巧
在 doDispatch 第一行打断点,用浏览器访问一个接口,单步跟 getHandler → getHandlerAdapter → applyPreHandle → ha.handle → applyPostHandle → processDispatchResult,观察 mappedHandler 里拦截器数量、mv 里的视图名。这是理解 MVC 运行时最直观的方式。
下一篇预告
第 17 篇:深入 HandlerMapping 与 HandlerAdapter 两大体系------@RequestMapping 是怎么被注册成映射的?适配器内部又如何反射调用你的 Controller 方法?
如果这篇对你有帮助,欢迎 点赞 · 收藏 · 关注 三连支持。
Spring 源码系列共 30 篇,由浅入深持续更新中。有疑问或想深挖的源码点,评论区告诉我,下篇见。