SpringMVC - DispatcherServlet
SpringMVC DispatcherServlet 源码分析
DispatcherServlet 是 SpringMVC 的前端控制器:Servlet 容器只知道把请求丢给一个 Servlet,它负责把”一个 HttpServletRequest”翻译成”一次 Java 方法调用”。
核心思路是双层策略:HandlerMapping 回答”这个请求归谁管”,HandlerAdapter 回答”这个 handler 怎么调”,DispatcherServlet 自己只编排流程,不认识任何具体的 Controller 签名。
// 基于 Spring Framework 5.3.39 (本地 JavaSourceReadingLab), org.springframework.web.servlet.DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
// doDispatch 是整条主线。所有 HTTP 方法都走这里,由 HandlerAdapter/handler 自己决定接不接受
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null; // handler + 拦截器链,一起返回
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null; // 关键设计:异常先存起来,不立刻抛
try {
processedRequest = checkMultipart(request); // 文件上传请求会被包装成 MultipartHttpServletRequest
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest); // 第一层策略:谁来处理
if (mappedHandler == null) {
noHandlerFound(processedRequest, response); // 404 或抛 NoHandlerFoundException
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 第二层策略:怎么调用
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return; // 304 缓存命中,直接短路
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return; // 任一拦截器 preHandle 返回 false 就终止,链内部已补偿 afterCompletion
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 真正执行 Controller
if (asyncManager.isConcurrentHandlingStarted()) {
return; // 异步模式(Callable/DeferredResult):本线程到此为止,响应留给异步线程
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv); // 拦截器 postHandle,逆序
}
catch (Exception ex) {
dispatchException = ex; // 不抛,落到 processDispatchResult 统一走异常解析器
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest); // 删临时文件
}
}
}
}
// 遍历所有 HandlerMapping,谁先认领谁赢。顺序由 Ordered 决定,RequestMappingHandlerMapping 排最前
@Nullable
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; // 返回的不是裸 handler,是 handler + 匹配到的拦截器
}
}
}
return null;
}
// handler 只是个 Object,DispatcherServlet 不认识它;靠 adapter.supports() 挑出会调它的适配器
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 [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
// 收尾:正常结果和异常在这里汇合,都被归一成"要不要渲染一个 ModelAndView"
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception); // 走 HandlerExceptionResolver 链,@ExceptionHandler 在这里生效
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response); // @ResponseBody 场景 mv 为 null,根本不进这里
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
// ... 省略 trace 日志
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null); // 拦截器 afterCompletion,逆序
}
}
}// 基于 Spring Framework 5.3.39 (本地 JavaSourceReadingLab), org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
// 只要是 HandlerMethod 一律接手。真正的匹配早在 HandlerMapping 阶段做完了,adapter 不再挑
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
// ha.handle() 最终落到这里
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request); // 校验 HTTP 方法是否被支持、是否要求 session
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
// ... 省略:可选的按 session 串行化,默认关闭
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// ... 省略 Cache-Control 处理
return mav;
}
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// ... 省略异步基础设施装配 (asyncWebRequest / taskExecutor / 拦截器注册)
ServletWebRequest webRequest = (asyncWebRequest instanceof ServletWebRequest ?
(ServletWebRequest) asyncWebRequest : new ServletWebRequest(request, response));
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 收集 @InitBinder 方法
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 收集 @ModelAttribute 方法
// HandlerMethod 只是"方法描述",每次请求包装成可执行的 ServletInvocableHandlerMethod(无状态→有状态)
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); // 全局共享的解析器链
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // 靠它从字节码里挖参数名
ModelAndViewContainer mavContainer = new ModelAndViewContainer(); // 本次请求的 model/view 状态载体
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod); // 先执行 @ModelAttribute 方法填充 model
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// ... 省略异步结果恢复分支 (asyncManager.hasConcurrentResult())
invocableMethod.invokeAndHandle(webRequest, mavContainer); // 参数解析→反射调用→返回值处理,全在这一句里
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest); // requestHandled=true 时返回 null
}
finally {
webRequest.requestCompleted();
}
}
// 参数解析器链的默认装配。顺序就是优先级,这个顺序本身是语义
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); // @RequestParam(严格模式)
resolvers.add(new PathVariableMethodArgumentResolver()); // @PathVariable
resolvers.add(new ServletModelAttributeMethodProcessor(false)); // @ModelAttribute
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); // @RequestBody
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); // @RequestHeader
// ... 省略其余注解型解析器
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver()); // 直接注入 HttpServletRequest 这类原生对象
resolvers.add(new ServletResponseMethodArgumentResolver());
// ... 省略其余类型解析器
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all:兜底。裸写 String id 没加注解,落到这里按 @RequestParam 默认规则处理
resolvers.add(new PrincipalMethodArgumentResolver());
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
// 返回值处理器链,同样顺序即优先级
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice)); // ResponseEntity
// ... 省略流式/异步返回值处理器
// Annotation-based return value types
handlers.add(new ServletModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice)); // @ResponseBody:走 MessageConverter 直写响应体
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler()); // 返回 String 默认当视图名,这就是为什么忘了 @ResponseBody 会 404 找视图
handlers.add(new MapMethodProcessor());
// ... 省略自定义与兜底
return handlers;
}
}// 基于 Spring Framework 5.3.39 (本地 JavaSourceReadingLab), org.springframework.web.method.support.InvocableHandlerMethod
public class InvocableHandlerMethod extends HandlerMethod {
// "HTTP → 方法调用"的最后一跳:先凑齐参数数组,再反射
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// ... 省略 trace 日志
return doInvoke(args);
}
// 逐个参数问一遍解析器链:谁 supports 谁上
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs); // 外部直供的参数(如 @ExceptionHandler 的异常对象)优先,按类型匹配
if (args[i] != null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) { // composite 内部有 参数→解析器 缓存,链只完整走第一次
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
// ... 省略 debug 日志
throw ex;
}
}
return args;
}
// 反射调用本体
@Nullable
protected Object doInvoke(Object... args) throws Exception {
Method method = getBridgedMethod(); // 泛型桥接方法处理,拿到真正带类型信息的方法
try {
if (KotlinDetector.isSuspendingFunction(method)) {
return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
}
return method.invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(method, getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
// 拆掉反射包装,让业务异常以原始类型抛出去,@ExceptionHandler 才能按异常类型匹配
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
}原理串讲
把一次 GET /users/1 从头走到尾。Tomcat 解析完 HTTP 报文,按 url-pattern 把请求交给 DispatcherServlet,经 HttpServlet.service → FrameworkServlet.processRequest → doService 一路落到 doDispatch。
找 handler。 getHandler 遍历 handlerMappings 列表,第一个是 RequestMappingHandlerMapping。
它的账本在启动时就建好了:容器初始化阶段扫描所有 bean,isHandler 筛出带 @Controller 或 @RequestMapping 的类,对每个方法调 getMappingForMethod——先解析方法上的 @GetMapping("/{id}") 生成 RequestMappingInfo,再和类上 @RequestMapping("/users") 的 info 做 combine,得到 GET /users/{id} 这条完整规则,注册进内部的 MappingRegistry。
运行期查找就是拿 /users/1 去 registry 里匹配 RequestMappingInfo(路径、方法、produces 等条件逐项比对,多个候选时排序取最优),命中后返回 HandlerMethod(bean + Method 的封装),再连同 URL 匹配到的拦截器一起打包成 HandlerExecutionChain。
为什么返回链而不是裸 handler?因为拦截器是”按 URL 配置”的横切逻辑,只有 HandlerMapping 知道 URL,让它在匹配时顺手把拦截器也定下来,DispatcherServlet 就完全不用关心拦截器和路径的对应关系。
找 adapter。 getHandlerAdapter 用 supports 试探,RequestMappingHandlerAdapter 对所有 HandlerMethod 返回 true。
这层看似多余——为什么不让 DispatcherServlet 直接调 HandlerMethod?因为 handler 在签名上只是 Object:老式的 Controller 接口、HttpRequestHandler、注解方法,各自的调用方式完全不同。
把”怎么调”抽成 HandlerAdapter,新增一种编程模型只需注册一个 adapter,doDispatch 一行不改,这是典型的开闭原则。
拦截器 preHandle。 HandlerExecutionChain.applyPreHandle 正序执行,每成功一个就记录 interceptorIndex;任何一个返回 false,立刻对”已经成功的那几个”逆序触发 afterCompletion 然后返回 false。
为什么要记 index?afterCompletion 语义是资源清理,只有 preHandle 成功过的拦截器才可能持有资源——没跑过 preHandle 的拦截器去清理,轻则空操作重则 NPE。这和 try/finally 的配对思想一致。
执行方法。 ha.handle → handleInternal → invokeHandlerMethod。
这里把无状态的 HandlerMethod 包装成本次请求专属的 ServletInvocableHandlerMethod,注入三样东西:参数解析器链、返回值处理器链、binderFactory。
然后 invokeAndHandle → invokeForRequest。getMethodArgumentValues 逐参数走解析器链:Long id 上有 @PathVariable,PathVariableMethodArgumentResolver 认领,从 request attribute 里取出 HandlerMapping 匹配阶段存好的 URI 模板变量表 {id=1},拿到字符串 “1”,再经 WebDataBinder 的类型转换体系变成 Long 1L。
参数凑齐后 doInvoke 反射调用 userController.getUser(1L)。
注意 composite 解析器有参数级缓存,同一个方法的同一个参数只在第一次请求时遍历整条链,之后直接命中,30 个解析器的链才敢做成线性查找。
返回值与收尾。 方法返回 User 对象,返回值处理器链里 RequestResponseBodyMethodProcessor 因 @RestController 上的 @ResponseBody 认领,做内容协商选中 Jackson 的 MessageConverter,把对象序列化直接写进响应体,并调 mavContainer.setRequestHandled(true)。
于是 getModelAndView 返回 null,doDispatch 里 mv 为 null,processDispatchResult 跳过 render,只逆序触发 afterCompletion,请求结束。
如果 Controller 中途抛异常,doDispatch 不让它直接炸出去,先存进 dispatchException 再统一交给 processDispatchResult → processHandlerException 走 HandlerExceptionResolver 链——@ExceptionHandler 能按异常类型匹配,正是靠 doInvoke 里把 InvocationTargetException 拆包、让业务异常以原始类型上抛。
为什么异常要延迟处理?因为”异常也要产出响应”(错误页/错误 JSON),把它归一成和正常 ModelAndView 同一条收尾路径,afterCompletion 也保证被触发,流程只有一个出口。
设计取舍
- HandlerMapping 与 HandlerAdapter 拆成两层,代价是多一次线性查找,换来 handler 类型完全开放;
supportsInternal直接 return true,说明匹配职责已前移到 mapping,adapter 不重复判断。 - 参数解析器链”顺序即优先级”:注解型在前、类型型居中、catch-all 兜底。同一个参数理论上多个解析器都能 supports,靠顺序消歧,所以自定义解析器插入位置本身就是语义。
- 每次请求 new 一个 ServletInvocableHandlerMethod 和 ModelAndViewContainer,用对象创建换线程安全——共享的解析器链无状态,可变状态全部请求私有,没有任何锁。
- 拦截器不是 Servlet Filter:它在 handler 匹配之后执行,拿得到 HandlerMethod,能做基于注解的权限判断;Filter 在 DispatcherServlet 之前,只见得到原始 request。
- 常见误区:以为
@ResponseBody的响应也经过 render。实际上 MessageConverter 在invokeAndHandle阶段就把响应体写完了,ModelAndView 为 null,视图体系全程未参与。