环境准备
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)
从堆栈上可以看出
- Tomcat线程池接收请求
- 入口线程:Tomcat的NIO线程池(ThreadPoolExecutor)中的某个线程(如http-nio-8080-exec-7)接收并开始处理请求。
- NIO模型:通过NioEndpoint和SocketProcessor处理Socket连接,实现非阻塞IO。
- 经过Tomcat容器级处理
- Valve链:请求依次通过Tomcat的StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve,完成容器层级的预处理(如权限检查、路径映射)。
- 适配器:通过CoyoteAdapter将Tomcat底层Connector的请求对象适配为Servlet API的HttpServletRequest。
- 过滤链(Filter Chain)执行
- 过滤器顺序:
- Tomcat内置过滤器:如WsFilter(处理WebSocket协议升级)。
- Spring注册的过滤器:按顺序执行RequestContextFilter(绑定请求上下文)、FormContentFilter(解析表单)、CharacterEncodingFilter(设置编码)。
- 责任链模式:每个过滤器通过ApplicationFilterChain.doFilter()传递请求,最终抵达Servlet。
- 进入Servlet层
- HttpServlet入口:请求到达jakarta.servlet.http.HttpServlet.service()方法,根据请求方法(GET/POST等)分发到doGet()或doPost()。
- Spring的FrameworkServlet:Spring MVC的FrameworkServlet(DispatcherServlet的父类)重写doGet(),调用processRequest()统一处理请求。
- 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请求的核心方法,主要职责包括:
- 确定请求处理器(Handler)和适配器(HandlerAdapter)。
- 处理Multipart请求(如文件上传)。
- 执行拦截器(Interceptor)的preHandle/postHandle方法。
- 调用处理器方法并生成ModelAndView。
- 处理视图渲染与异常。
- 管理异步请求和资源清理。
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"; // 字符串返回值
}
流程:
- returnValue = "home"。
- ViewNameMethodReturnValueHandler处理,将视图名写入mavContainer。
- 后续流程通过ViewResolver解析视图并渲染。
5.2 返回JSON数据
java
@GetMapping("/api/data")
@ResponseBody
public Data getData() {
return new Data(); // 需要Jackson库支持
}
流程:
- returnValue = Data对象。
- RequestResponseBodyMethodProcessor处理,将对象序列化为JSON并写入响应体。
- 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); // 统一包装响应
}
}