Spring MVC-DispatcherServlet 的源码解析

上篇文章把整个MVC的架构和核心流程介绍了一下,其中多次提到DispatcherServlet整个组件,我们知道整个流程看下来DispatcherServlet是一个核心组件,接收请求、分发请求给控制器进行处理。这个组件继承自FrameworkServlet和HttpServlet,然后与HandlerMapping,HandlerAdapter,ViewResolver等组件,完成了从请求接受到响应返回到完整流程。

如果你去看Spring Framework的参考文档,DispatcherServlet的主要职责是这样描述的:

  • 初始化Web应用程序上下文(WebApplicationContext)和核心组件
  • 根据请求路径和方法分派请求到控制器
  • 处理视图解析和渲染
  • 支持异常处理、国际化、文件上传等高级功能

1. DispatcherServlet 的继承关系与初始化过程

1.1 继承关系

我们可以看到,DispatcherServlet是直接继承FrameworkServlet

然后FrameworkServlet则是继承HttpServlet,实现了ApplicationContextAware接口,这里正好用这个来解释下extends和implements的区别。

这里我们可以看到DispatcherServlet extends FrameworkServletBean,意思是:

  • 初始化参数注入(initServletBean())
  • 处理Servlet生命周期
  • 读取初始化参数到Spring的Bean属性里

而implements ApplicationContextAware ,首先这个接口的作用是Spring容器在创建Bean时,把当前ApplicationContext(应用上下文)注入到Bean中。所以实现这个接口的目的是,感知容器实现自定义接口中的方法。

在这里我们可以看出来,extends是继承已有逻辑,implements是遵循外部规范。

1.2 初始化过程

DispatcherServlet 的初始化发生在 Servlet 容器(如 Tomcat)启动时,主要通过 init 方法触发,最终调用 onRefresh 方法完成组件初始化。以下是关键源码分析:

1.2.1 init方法(来自HttpSevletBean)

scala 复制代码
public abstract class HttpServletBean extends HttpServlet {
    @Override
    public void init() throws ServletException {
        // 设置 Servlet 配置参数
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
        bw.setPropertyValues(pvs, true);
        // 调用子类的初始化方法
        initServletBean();
    }
}

这个方法的作用就是将Servlet配置注入到DispatcherServlet。

1.2.2 initServletBean

FrameworkServlet 重写了 initServletBean,初始化 Web 上下文:

scala 复制代码
public abstract class FrameworkServlet extends HttpServletBean {
    @Override
    protected void initServletBean() throws ServletException {
        try {
            this.webApplicationContext = initWebApplicationContext();
            initFrameworkServlet();
        } catch (Exception ex) {
            throw new ServletException("Context initialization failed", ex);
        }
    }

    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
        // 创建或获取 WebApplicationContext
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext) wac);
            }
        }
        if (wac == null) {
            wac = createWebApplicationContext(rootContext);
        }
        // 发布上下文到 ServletContext
        if (!this.refreshEventReceived) {
            onRefresh(wac);
        }
        return wac;
    }
}

这里主要是调用onRefresh触发子类的初始化逻辑,关键的点是webApplicationContext是Spring MVC的IoC容器,管理着MVC的所有相关Bean。

1.2.3 onRefresh方法

这个方法就是要初始化MVC的核心组件:

scss 复制代码
public class DispatcherServlet extends FrameworkServlet {
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }
}

我们在上节讲到的核心组件都是在这里初始化的。

2. 请求分发核心逻辑:doDispatch方法

我们说过DispatcherServlet 还有一个核心职责是处理 HTTP 请求,其请求分发的核心方法是 doDispatch,位于 DispatcherServlet 类中。以下是 doDispatch 的源码分析:

ini 复制代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

        try {
            // 检查是否为 multipart 请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 获取 HandlerExecutionChain
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 获取 HandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // 处理 Last-Modified 头部(用于缓存)
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 执行拦截器的 preHandle 方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 调用 HandlerAdapter 处理请求
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            // 处理异步请求
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            // 设置默认视图名(如果未指定)
            applyDefaultViewName(processedRequest, mv);

            // 执行拦截器的 postHandle 方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception ex) {
            dispatchException = ex;
        } catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }

        // 处理结果(视图渲染或异常处理)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
        }
    }
}

从这个源码能够看出来整个的核心步骤:

检查multipart --> 获取HandlerExceptionChain --> 获取HandlerAdapter --> 处理Last- Modified缓存 --> 执行拦截器preHandler --> 调用HandlerAdapter --> 执行拦截器postHandler --> 处理结果

整个源码的关键是:HandlerExecutionChain,主要是调用getHandler遍历所有HandlerMapping查找匹配的HandlerExecutionChain(包含Handler和拦截器)。

asyncManager.isConcurrentHandlingStarted()支持异步请求。

3. 总结

这篇文章主要就是说了DispatcherServlet,DispatcherServlet 是 Spring MVC 的核心调度器,通过初始化九大组件和 doDispatch 方法,协调请求的映射、处理和视图渲染。另外,也可以支持异步处理和异常处理。

相关推荐
拆房老料10 分钟前
【第四部分:Agentic 智能体设计模式】16. 一个 Prompt 搞不定复杂任务?试试 Prompt Chaining
java·前端·人工智能·设计模式·prompt
张张123y1 小时前
后端第十四课:Agent 记忆系统(让 Agent 记住上下文和用户,跨会话不健忘)
java·大数据·人工智能·python·agent·记忆
曹牧5 小时前
C#:空合并运算符
java·前端·数据库
布吉岛的石头6 小时前
Java 程序员第 50 阶段2:预训练的目标函数:自回归语言建模本质
java·开发语言·人工智能·深度学习·回归·transformer
golang学习记6 小时前
IDEA 2026年的玩法已经完全不同
java·ide·intellij-idea
紧跟先前的步伐6 小时前
Go AI Agent 实战 05|Temperature 与生成参数:让模型输出可控
java·人工智能·golang
金銀銅鐵7 小时前
[Java] 展示添加元素时 ArrayList 的内部变化
java·后端·ai编程
斌糖雪梨7 小时前
spring auth 核心流程详解
java·后端·spring
文丑颜不良啊8 小时前
LeetCode201~225题目解析
java·leetcode
SL_staff10 小时前
4G设备掉线三层归因指南:SIM卡、模组、JVS-IOT网关配置精准锁定
java·物联网·产品