Spring 机制六: MVC 全链路源码解析:从 DispatcherServlet 到返回值解析(超硬核源码深度)

Spring MVC 是 Spring 框架的核心模块之一,其请求处理机制以 DispatcherServlet 为中心,实现高效的请求分发、处理和响应渲染。本指南基于 Spring Framework 6.x+ 版本(2026 年最新),通过源码级深度剖析全链路:从 DispatcherServlet 的初始化,到请求接收、Handler 映射、执行、异常处理,直至 View 解析和返回值渲染。所有源码片段来源于官方仓库(org.springframework.web.servlet.DispatcherServlet),结合实战配置示例,帮助你彻底掌握。

为了直观,我们先看 Spring MVC 请求处理流程图:

1. DispatcherServlet 概述与初始化

DispatcherServlet 是 Spring MVC 的前端控制器(Front Controller),继承自 HttpServlet,负责接收所有 HTTP 请求,并根据配置委托给合适的组件处理。它不直接处理业务逻辑,而是协调 HandlerMapping、HandlerAdapter 等组件,形成 MVC 模式。

初始化过程(init 方法)

  • 加载上下文:DispatcherServlet 在 Servlet 初始化时加载 WebApplicationContext(默认从 XML 或注解配置)。
  • 检测组件:自动检测并注册默认的 HandlerMapping、HandlerAdapter、ViewResolver 等(如果未自定义)。
  • 关键源码(DispatcherServlet.initStrategies):
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}
  • 配置示例(Java 配置,使用 @EnableWebMvc):
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example")
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}
  • web.xml 配置(传统方式):
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

2. 请求处理全链路:doService 与 doDispatch

请求到达 DispatcherServlet 后,首先调用 doService(HttpServlet 的入口),然后进入核心方法 doDispatch。这里是全链路的灵魂,处理从请求映射到响应渲染的所有步骤。

doService 源码剖析

  • 准备请求:设置请求属性,如 WebApplicationContext。
  • 委托 doDispatch:核心分发逻辑。
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // ... 日志和属性设置
    try {
        doDispatch(request, response);
    } finally {
        // 清理
    }
}

doDispatch 源码深度解析(全链路步骤)

doDispatch 是 DispatcherServlet 的心脏,逐行剖析:

  1. 检查 Multipart:如果有文件上传,使用 MultipartResolver 包装请求。
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
// ... 检查 Multipart
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
  1. 获取 Handler:通过 HandlerMapping(如 RequestMappingHandlerMapping)查找匹配的 Handler(@Controller 方法)。
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
    noHandlerFound(processedRequest, response);
    return;
}
  1. 获取 Adapter:使用 HandlerAdapter(如 RequestMappingHandlerAdapter)执行 Handler。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  1. 执行拦截器 preHandle:HandlerInterceptor 的前置处理。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
}
  1. 执行 Handler:调用实际的 Controller 方法,返回 ModelAndView。
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  1. 执行拦截器 postHandle:后置处理。
mappedHandler.applyPostHandle(processedRequest, response, mv);
  1. 处理结果:渲染 View 或处理异常。
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  • 完整 doDispatch 源码 skeleton
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 步骤1: Multipart 检查
    // 步骤2: HandlerMapping 获取 HandlerExecutionChain
    // 步骤3: HandlerAdapter 获取
    // 步骤4: preHandle
    // 步骤5: handle 执行
    // 步骤6: postHandle
    // 步骤7: processDispatchResult (View 渲染或异常)
    // finally: afterCompletion
}

3. 核心组件深度:HandlerMapping 与 HandlerAdapter

  • HandlerMapping:映射请求到 Handler。默认:RequestMappingHandlerMapping(基于 @RequestMapping)。
  • 源码:AbstractHandlerMapping.getHandler() 通过 URL 匹配 Annotation。
  • HandlerAdapter:执行 Handler。默认:RequestMappingHandlerAdapter。
  • 支持 @Controller、参数解析(@PathVariable 等)、返回值处理(@ResponseBody)。
  • 源码:handleInternal() 调用 invokeHandlerMethod() 执行方法。

示例 Controller:

@Controller
@RequestMapping("/api")
public class ExampleController {
    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "Hello, Spring MVC!");
        return "helloView";  // 逻辑视图名
    }
}

4. 异常处理:HandlerExceptionResolver

  • 默认:DefaultHandlerExceptionResolver 处理标准异常;@ExceptionHandler 支持自定义。
  • 源码:processHandlerException() 遍历 Resolvers。

示例:

@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception ex) {
    ModelAndView mav = new ModelAndView("error");
    mav.addObject("error", ex.getMessage());
    return mav;
}

5. 返回值解析与 ViewResolver

  • ModelAndView 处理:如果返回 ModelAndView 或 String(视图名),ViewResolver 解析为实际 View(如 JSP)。
  • @ResponseBody:HttpMessageConverter 直接序列化 JSON/XML(Jackson/Gson)。
  • ViewResolver:InternalResourceViewResolver 拼接 prefix + viewName + suffix。

源码:render() in DispatcherServlet:

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Locale/Theme 应用
    View view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
    view.render(mv.getModelInternal(), request, response);
}

总结与最佳实践

通过以上源码剖析,你看到 DispatcherServlet 如何协调组件实现 MVC 全链路:高效、模块化、可扩展。实践建议:在 IntelliJ 中调试 DispatcherServlet.doDispatch,逐步跟踪。进一步探索:Spring Boot 的自动配置简化了这些(@SpringBootApplication 隐含 @EnableWebMvc)。

如果需要特定版本源码 diff 或扩展如 REST 支持,随时提供细节!🚀

文章已创建 3707

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部