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.serviceFrameworkServlet.processRequestdoService 一路落到 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。 getHandlerAdaptersupports 试探,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.handlehandleInternalinvokeHandlerMethod
这里把无状态的 HandlerMethod 包装成本次请求专属的 ServletInvocableHandlerMethod,注入三样东西:参数解析器链、返回值处理器链、binderFactory。
然后 invokeAndHandleinvokeForRequestgetMethodArgumentValues 逐参数走解析器链: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 再统一交给 processDispatchResultprocessHandlerException 走 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,视图体系全程未参与。

延伸阅读