SpringMVC的执行过程

环境准备

java 复制代码
package org.example.springmvclearn;

public record Greeting(long id, String content) { }
java 复制代码
package org.example.springmvclearn;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}
java 复制代码
package org.example.springmvclearn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringMvcLearnApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringMvcLearnApplication.class, args);
    }

}
properties 复制代码
spring.application.name=SpringMVCLearn
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.4</version>
    </parent>
    <groupId>org.example</groupId>
    <artifactId>SpringMVCLearn</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringMVCLearn</name>
    <description>SpringMVCLearn</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

浏览器访问**http://localhost:8080/greeting**

会返回

json 复制代码
{
    "id": 1,
    "content": "Hello, World!"
}

GET请求到SpringMVC

先来看下从Http的GET请求是怎么走到SpringMVC的

堆栈信息

log 复制代码
http-nio-8080-exec-7@6013" daemon prio=5 tid=0x23 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
	  at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:941)
	  at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
	  at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
	  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
	  at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
	  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
	  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
	  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	  at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
	  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
	  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
	  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
	  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
	  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
	  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
	  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
	  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
	  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
	  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	  at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
	  at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
	  at java.lang.Thread.run(Thread.java:833)

从堆栈上可以看出

  1. Tomcat线程池接收请求
  • 入口线程:Tomcat的NIO线程池(ThreadPoolExecutor)中的某个线程(如http-nio-8080-exec-7)接收并开始处理请求。
  • NIO模型:通过NioEndpoint和SocketProcessor处理Socket连接,实现非阻塞IO。
  1. 经过Tomcat容器级处理
  • Valve链:请求依次通过Tomcat的StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve,完成容器层级的预处理(如权限检查、路径映射)。
  • 适配器:通过CoyoteAdapter将Tomcat底层Connector的请求对象适配为Servlet API的HttpServletRequest。
  1. 过滤链(Filter Chain)执行
  • 过滤器顺序:
    • Tomcat内置过滤器:如WsFilter(处理WebSocket协议升级)。
    • Spring注册的过滤器:按顺序执行RequestContextFilter(绑定请求上下文)、FormContentFilter(解析表单)、CharacterEncodingFilter(设置编码)。
  • 责任链模式:每个过滤器通过ApplicationFilterChain.doFilter()传递请求,最终抵达Servlet。
  1. 进入Servlet层
  • HttpServlet入口:请求到达jakarta.servlet.http.HttpServlet.service()方法,根据请求方法(GET/POST等)分发到doGet()或doPost()。
  • Spring的FrameworkServlet:Spring MVC的FrameworkServlet(DispatcherServlet的父类)重写doGet(),调用processRequest()统一处理请求。
  1. DispatcherServlet分发请求
  • 核心入口:最终由DispatcherServlet.doService()接管,执行Spring MVC的核心流程

graph TD A[Tomcat线程池<br>(NIO Worker线程)] B[Tomcat Valve链<br> (容器处理)] C[CoyoteAdapter<br>(协议适配)] D[Filter链<br>(Tomcat+Spring)] E[HttpServlet.service] F[FrameworkServlet.doGet] G[DispatcherServlet.doService] H[Spring MVC完整流程] C --> D D --> E E --> F F --> G G --> H subgraph Tomcat容器处理 A --> B --> C end subgraph Filter层 D --> D1[Tomcat WsFilter] D --> D2[Spring RequestContextFilter] D --> D3[Spring FormContentFilter] D --> D4[Spring CharacterEncodingFilter] end subgraph SpringMVC处理 H --> H1[HandlerMapping] H --> H2[HandlerInterceptor] H --> H3[Controller] H --> H4[ViewResolver] end

SpringMVC开始处理请求

我们直接从DispatcherServlet#doService开始分析

doService

java 复制代码
	/**
	 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
	 * for the actual dispatching.
	 */
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 记录请求的详细信息,用于调试和监控。
		logRequest(request);

		// Keep a snapshot of the request attributes in case of an include,
		// to be able to restore the original attributes after the include.
		Map<String, Object> attributesSnapshot = null;
        // 如果是include请求,创建属性快照(attributesSnapshot)
		if (WebUtils.isIncludeRequest(request)) {
            // 保存当前请求属性快照
			attributesSnapshot = new HashMap<>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
                // 仅保存以org.springframework.web.servlet(DEFAULT_STRATEGIES_PREFIX)开头的属性或cleanupAfterInclude启用时的所有属性。
                // 在finally块中通过restoreAttributesAfterInclude恢复原始属性。
				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		// Make framework objects available to handlers and view objects.
        // 设置框架级属性
        // 当前应用的WebApplicationContext
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); 
        // 用于解析区域设置的LocaleResolver
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        // 主题解析器
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        // 主题资源
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());


        // 管理Flash作用域
		if (this.flashMapManager != null) {
            // 处理重定向时的数据传递(如Post-Redirect-Get模式)
            // 从上一个请求中读取Flash数据(如重定向前的表单数据)
			FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
			if (inputFlashMap != null) {
				request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
			}
            // 存储当前请求需要传递到下一个重定向请求的数据。
			request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
            // 管理Flash数据的存储与检索
			request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
		}

        // 解析请求路径 
		RequestPath previousRequestPath = null;
		if (this.parseRequestPath) {
            // 解析并缓存请求路径信息(如URL、URI),用于后续路由匹配。
			previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
			ServletRequestPathUtils.parseAndCache(request);
		}

		try {
            // 请求分发(核心逻辑)
			doDispatch(request, response);
		}
		finally {
            // 清理资源
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
			if (this.parseRequestPath) {
				ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
			}
		}
	}

doDispatch

doDispatch是实际处理HTTP请求的核心方法,主要职责包括:

  1. 确定请求处理器(Handler)和适配器(HandlerAdapter)。
  2. 处理Multipart请求(如文件上传)。
  3. 执行拦截器(Interceptor)的preHandle/postHandle方法。
  4. 调用处理器方法并生成ModelAndView。
  5. 处理视图渲染与异常。
  6. 管理异步请求和资源清理。
java 复制代码
	/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	@SuppressWarnings("deprecation")
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 可能被包装的请求对象(如处理Multipart请求)
		HttpServletRequest processedRequest = request;
        // 包含处理器(Handler)和拦截器链的HandlerExecutionChain。
		HandlerExecutionChain mappedHandler = null;
        // 标记是否已解析Multipart请求。
		boolean multipartRequestParsed = false;
        // 管理异步请求的核心对象。
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
                // 检查是否为Multipart请求(如multipart/form-data),如果是则将其包装为MultipartHttpServletRequest。
				processedRequest = checkMultipart(request);
                // 若请求被包装,multipartRequestParsed设为true,后续需要清理临时文件。
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
                // 遍历所有注册的HandlerMapping,找到匹配当前请求的处理器链。
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
                    // 若未找到处理器,返回404错误
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
                // 遍历所有HandlerAdapter,找到支持当前处理器类型的适配器。
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
                // 处理Last-Modified头(缓存优化)
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
                // 检查资源是否已修改,若未修改则直接返回304状态码(避免重复传输)
				if (isGet || HttpMethod.HEAD.matches(method)) {
                    // 仅对GET/HEAD请求生效,依赖处理器的getLastModified方法。
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

                // 执行拦截器的preHandle方法
                // 按顺序执行拦截器的preHandle方法  若某个拦截器返回false,终止请求处理并返回。
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
                // 通过适配器执行处理器方法,返回ModelAndView。
                // 处理器可能是@Controller注解的类、HttpRequestHandler或其他类型。
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
                    // 如果处理器启动了异步处理(如返回DeferredResult或Callable),直接返回,后续由异步线程处理
					return;
				}
                // 若ModelAndView未设置视图名,使用默认视图名。
				applyDefaultViewName(processedRequest, mv);
                // 逆序执行拦截器的postHandle方法。
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			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 ServletException("Handler dispatch failed: " + err, err);
			}
            // 处理分发结果与异常
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new ServletException("Handler processing failed: " + err, err));
		}
		finally {
            //  资源清理与异步支持
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
				asyncManager.setMultipartRequestParsed(multipartRequestParsed);
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed || asyncManager.isMultipartRequestParsed()) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

1. getHandler

getHandler方法的核心职责是遍历所有已注册的HandlerMapping,找到能够处理当前请求的处理器链。

  • 按顺序尝试所有处理器映射:确保优先级高的HandlerMapping优先匹配。

  • 返回处理器链(HandlerExecutionChain):包含实际处理器(Handler)和关联的拦截器(Interceptors)。

  • 未找到处理器时返回null:触发后续的noHandlerFound逻辑(返回404)。

java 复制代码
	/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
	 */
	@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;
				}
			}
		}
		return null;
	}

HandlerMapping是请求与处理器之间的映射策略,不同实现类的职责:

  • RequestMappingHandlerMapping:处理@Controller注解类中的@RequestMapping方法(最常用)。

  • BeanNameUrlHandlerMapping:根据Bean名称与URL路径匹配(传统方式)。

  • SimpleUrlHandlerMapping:显式配置URL路径与处理器的映射(如静态资源处理)。

  • RouterFunctionMapping:支持函数式编程模型的WebFlux风格路由(Spring 5+)。

  • WelcomePageHandlerMapping:处理根路径请求(如 / 或 /index),返回应用的默认欢迎页(例如 index.html)

  • WelcomePageNotAcceptableHandlerMapping:处理根路径请求但客户端不接受HTML响应的情况,返回 406 Not Acceptable 状态码。

HandlerExecutionChain的结构

java 复制代码
public class HandlerExecutionChain {

	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

	private final Object handler; // 实际处理器(如Controller方法)

	private final List<HandlerInterceptor> interceptorList = new ArrayList<>(); // 拦截器链

	private int interceptorIndex = -1;

	...
}

这里匹配的是常用的RequestMappingHandlerMapping

2. HandlerAdapter

java 复制代码
	/**
	 * Return the HandlerAdapter for this handler object.
	 * @param handler the handler object to find an adapter for
	 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
	 */
	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");
	}
  • RequestMappingHandlerAdapter:处理基于注解的Controller
  • HttpRequestHandlerAdapter:处理静态资源或低级HTTP操作
  • SimpleControllerHandlerAdapter:传统Spring MVC Controller
  • HandlerFunctionAdapter:Spring WebFlux 中用于支持函数式编程风格处理请求的适配器。

这里匹配的是常用的RequestMappingHandlerAdapter

3. handleInternal

java 复制代码
	@Override
	@Nullable
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
		//  请求校验
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		// 会话同步控制
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					// 调用方法
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
		// 响应缓存控制
		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			// 存在会话属性:设置短缓存或no-cache(默认cacheSecondsForSessionAttributeHandlers=0,即Cache-Control: no-store)。
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				// 使用默认缓存策略(如prepareResponse可能设置Cache-Control: private)。
				prepareResponse(response);
			}
		}

		return mav;
	}

4. invokeHandlerMethod

java 复制代码
	/**
	 * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
	 * if view resolution is required.
	 * @since 4.2
	 * @see #createInvocableHandlerMethod(HandlerMethod)
	 */
	@SuppressWarnings("deprecation")
	@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		
		// 初始化异步请求管理器
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  // WebAsyncManager:管理异步请求的核心组件
		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout); // asyncRequestTimeout(默认由服务器配置)。

		asyncManager.setTaskExecutor(this.taskExecutor); // taskExecutor(异步任务线程池)。
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors); // 注册Callable和DeferredResult的拦截器。
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		// Obtain wrapped response to enforce lifecycle rule from Servlet spec, section 2.3.3.4

		// 包装请求与响应
		// 将原生HttpServletRequest/Response包装为Spring的请求对象,提供便捷的访问方法。
		response = asyncWebRequest.getNativeResponse(HttpServletResponse.class);
		ServletWebRequest webRequest = (asyncWebRequest instanceof ServletWebRequest ?
				(ServletWebRequest) asyncWebRequest : new ServletWebRequest(request, response));


		// 准备数据绑定与模型工厂

		// 创建WebDataBinder实例,处理数据绑定与验证(如@Valid注解)
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		// 初始化模型数据(@ModelAttribute方法的结果)。
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

		// 创建可调用的处理器方法
		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		if (this.argumentResolvers != null) {
			// 解析方法参数(如@RequestParam、@RequestBody)
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); 
		}
		if (this.returnValueHandlers != null) {
			// 处理返回值(如转换为JSON或视图名)
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		// 用于参数绑定与验证
		invocableMethod.setDataBinderFactory(binderFactory);
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		invocableMethod.setMethodValidator(this.methodValidator);

		// 初始化模型容器
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		// 存储模型数据与视图信息。
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		// 执行@ModelAttribute方法,填充模型数据。
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		// 处理异步并发结果
		if (asyncManager.hasConcurrentResult()) {
			Object result = asyncManager.getConcurrentResult();
			Object[] resultContext = asyncManager.getConcurrentResultContext();
			Assert.state(resultContext != null && resultContext.length > 0, "Missing result context");
			// 获取异步结果并包装到mavContainer。
			mavContainer = (ModelAndViewContainer) resultContext[0];
			asyncManager.clearConcurrentResult();
			LogFormatUtils.traceDebug(logger, traceOn -> {
				String formatted = LogFormatUtils.formatValue(result, !traceOn);
				return "Resume with async result [" + formatted + "]";
			});
			// 重新创建invocableMethod以处理结果。
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}

		// 调用方法并处理返回值
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

		// 合并模型数据与视图信息,生成最终的ModelAndView对象。
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}

HandlerMethodArgumentResolver 有很多个

HandlerMethodReturnValueHandler

5. invokeAndHandle

java 复制代码
	/**
	 * Invoke the method and handle the return value through one of the
	 * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
	 * @param webRequest the current request
	 * @param mavContainer the ModelAndViewContainer for this request
	 * @param providedArgs "given" arguments matched by type (not resolved)
	 */
	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 执行Controller方法
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		// 设置响应状态
		setResponseStatus(webRequest);

		//  处理返回值为null的场景
		if (returnValue == null) {
			// isRequestNotModified:请求资源未修改(返回304状态码)。
			// getResponseStatus() != null:控制器已明确设置响应状态(如@ResponseStatus(HttpStatus.NOT_FOUND))。
			// mavContainer.isRequestHandled():请求已被标记为完成(如直接写入响应体)。
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				// 禁用内容缓存:避免浏览器或代理缓存无效响应。
				disableContentCachingIfNecessary(webRequest);
				// 标记请求完成:跳过后续视图渲染。
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		//  处理非null返回值但包含响应原因的场景
		//  Controller 方法设置了@ResponseStatus(reason = "自定义原因")。
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}
		
		mavContainer.setRequestHandled(false);
		Assert.state(this.returnValueHandlers != null, "No return value handlers");
		try {
			// 使用返回值处理器处理返回值
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(formatErrorForReturnValue(returnValue), ex);
			}
			throw ex;
		}
	}

常见的场景:

5.1 返回视图名
java 复制代码
@GetMapping("/home")
public String home(Model model) {
    model.addAttribute("message", "Hello");
    return "home"; // 字符串返回值
}

流程:

  1. returnValue = "home"。
  2. ViewNameMethodReturnValueHandler处理,将视图名写入mavContainer。
  3. 后续流程通过ViewResolver解析视图并渲染。
5.2 返回JSON数据
java 复制代码
@GetMapping("/api/data")
@ResponseBody
public Data getData() {
    return new Data(); // 需要Jackson库支持
}

流程:

  1. returnValue = Data对象。
  2. RequestResponseBodyMethodProcessor处理,将对象序列化为JSON并写入响应体。
  3. mavContainer.setRequestHandled(true),跳过视图渲染。

6. invokeForRequest

java 复制代码
	@Nullable
	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 使用HandlerMethodArgumentResolver解析参数(如@RequestParam、@RequestBody)。
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}

		if (shouldValidateArguments() && this.methodValidator != null) {
			this.methodValidator.applyArgumentValidation(
					getBean(), getBridgedMethod(), getMethodParameters(), args, this.validationGroups);
		}
		// 调用Controller方法
		Object returnValue = doInvoke(args);

		if (shouldValidateReturnValue() && this.methodValidator != null) {
			this.methodValidator.applyReturnValueValidation(
					getBean(), getBridgedMethod(), getReturnType(), returnValue, this.validationGroups);
		}
		// 可能为视图名、ModelAndView对象、@ResponseBody注解的返回值等
		return returnValue;
	}

7. handleReturnValue

java 复制代码
	/**
	 * Iterate over registered {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers} and invoke the one that supports it.
	 * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
	 */
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}

这里会用到RequestResponseBodyMethodProcessor

java 复制代码
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
		
		// 标记请求已处理 告知Spring MVC框架无需进行视图解析,响应体已直接处理。
		mavContainer.setRequestHandled(true);
		// 创建HTTP消息对象 将原生HttpServletRequest/Response包装为Spring的HTTP消息接口,提供统一的操作方法。
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
		// 处理ProblemDetail类型的返回值
		if (returnValue instanceof ProblemDetail detail) {
			// 设置HTTP状态码:从ProblemDetail中提取状态码。
			outputMessage.setStatusCode(HttpStatusCode.valueOf(detail.getStatus()));
			if (detail.getInstance() == null) {
				URI path = URI.create(inputMessage.getServletRequest().getRequestURI());
				// 填充instance字段:若未设置,默认使用当前请求路径。
				detail.setInstance(path);
			}
			// 调用错误拦截器:允许通过ErrorResponseInterceptor自定义错误响应(如日志记录或添加额外头信息)。
			invokeErrorResponseInterceptors(detail, null);
		}

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

至此SpringMVC 就将一个HTTP请求 执行完Controller 方法,经过writeWithMessageConverters 将Object 转成json 返回到前端了

8. getModelAndView

java 复制代码
	@Nullable
	private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
		// 更新模型数据
		modelFactory.updateModel(webRequest, mavContainer);
		// 检查请求是否已处理
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		ModelMap model = mavContainer.getModel();
		// 构建ModelAndView对象
		// mavContainer.getViewName()(由控制器方法返回的字符串,如"home")。
		// mavContainer.getModel()(包含@ModelAttribute和控制器方法添加的属性)。
		// mavContainer.getStatus()(如控制器方法设置的@ResponseStatus)。
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		// 处理重定向的Flash属性
		if (model instanceof RedirectAttributes redirectAttributes) {
			Map<String, ?> flashAttributes = redirectAttributes.getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			if (request != null) {
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
		}
		return mav;
	}

总结:

graph TD A[前端发起 HTTP 请求] --> B[SpringMVC DispatcherServlet] B --> C[HandlerMapping<br/>匹配请求路径] C --> D[HandlerExecutionChain<br/>包含拦截器与处理器] D --> E[HandlerAdapter<br/>适配调用 Controller] E --> F[Controller 方法执行<br/>@RequestMapping / @RestController] F --> G[返回 Java 对象] G --> H[HttpMessageConverter<br/>将 Java 对象转换为 JSON] H --> I[写入 HTTP 响应体] I --> J[前端接收 JSON 响应]

常用扩展:

全局处理

java 复制代码
public record ApiResponse(int code, String msg, Object data) {
}
java 复制代码
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
public class CustomResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true; // 对所有返回值生效
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType mediaType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return new ApiResponse(200, "Success", body); // 统一包装响应
    }
}