DispatcherServlet

Spring MVC DispatcherServlet 详解:前端控制器的配置、源码与核心流程

DispatcherServlet 是 Spring MVC 的前端控制器(Front Controller),作为整个框架的入口,统一接收并调度所有 HTTP 请求,协调 HandlerMapping、HandlerAdapter、ViewResolver 等组件完成请求处理与响应生成。其核心价值在于解耦组件依赖,通过 “统一入口 + 策略模式” 让各组件专注于单一职责(如 URL 映射、参数绑定、视图渲染)。从 “配置方式→初始化流程→请求处理流程→核心组件协作” 四个维度,彻底解析 DispatcherServlet 的工作机制。

DispatcherServlet 核心定位与配置

DispatcherServlet 本质是一个标准的 Servlet(继承 HttpServlet),需在 Web 应用中配置才能生效。根据 Servlet 版本不同,分为 web.xml 配置(Servlet 2.5 及以下)和 注解配置(Servlet 3.0+)两种方式。

1. 传统配置:web.xml 方式

通过 web.xml 声明 DispatcherServlet,指定配置文件路径、映射规则及静态资源处理策略,是早期项目的主流配置方式。

完整 web.xml 配置示例
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="4.0">

    <!-- 1. 处理静态资源(避免 DispatcherServlet 拦截 .html 文件) -->
    <servlet-mapping>
        <servlet-name>default</servlet-name> <!-- 容器默认 Servlet,负责处理静态资源 -->
        <url-pattern>*.html</url-pattern>    <!-- .html 后缀的请求交给默认 Servlet -->
    </servlet-mapping>

    <!-- 2. 配置 DispatcherServlet(Spring MVC 前端控制器) -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        
        <!-- 初始化参数:指定 Spring MVC 配置文件路径(默认:/WEB-INF/<servlet-name>-servlet.xml) -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value> <!-- 类路径下的配置文件 -->
        </init-param>
        
        <!-- 启动顺序:值为非负整数,容器启动时初始化(值越小优先级越高) -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- 3. 配置 DispatcherServlet 映射规则 -->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <!-- 映射路径:/ 表示拦截所有未被其他 Servlet 匹配的请求(除 .jsp 外) -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 4. 可选:配置 ContextLoaderListener(创建根容器,用于业务层 Bean) -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value> <!-- 业务层配置文件 -->
    </context-param>
</web-app>
关键配置解析
配置项 作用描述
init-param: contextConfigLocation 指定 Spring MVC 配置文件路径(如 classpath:springmvc.xml),若不配置则默认加载 /WEB-INF/DispatcherServlet-servlet.xml
load-on-startup: 1 容器启动时初始化 DispatcherServlet,避免首次请求时的初始化延迟;值越小,初始化优先级越高
url-pattern: / 拦截所有未被其他 Servlet 匹配的请求(如 /user/list/api/login),但不拦截 .jsp(由 Tomcat 的 JspServlet 处理)
静态资源映射(default Servlet) .html 等静态资源交给容器默认 Servlet 处理,避免 DispatcherServlet 拦截无法解析

2. 现代配置:Servlet 3.0+ 注解方式

Servlet 3.0 规范支持 “无 XML 配置”,Spring 通过 WebApplicationInitializer 接口实现自动注册。只需继承 AbstractAnnotationConfigDispatcherServletInitializer 并实现核心方法,即可替代 web.xml

注解配置示例
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

// 继承抽象类,替代 web.xml 配置
public class MyDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * 1. 根容器配置类(对应 ContextLoaderListener 加载的业务层配置)
     * 返回 null 表示无需根容器,仅使用 DispatcherServlet 的子容器
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{RootConfig.class}; // 业务层配置(Service、Dao 等)
    }

    /**
     * 2. DispatcherServlet 子容器配置类(MVC 层配置)
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class}; // MVC 配置(Controller、ViewResolver 等)
    }

    /**
     * 3. DispatcherServlet 映射路径(同 web.xml 的 <url-pattern>)
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"}; // 拦截所有请求
    }
}

// ---------------------- 配置类实现 ----------------------
// 1. 根容器配置(业务层)
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

@Configuration
// 扫描业务层组件,排除 Controller(交给子容器处理)
@ComponentScan(basePackages = "com.example", excludeFilters = {
    @ComponentScan.Filter(type = org.springframework.context.annotation.FilterType.ANNOTATION, value = Controller.class)
})
public class RootConfig {
    // 配置数据源、事务管理器等业务层组件
}

// 2. MVC 子容器配置(Web 层)
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc // 启用 Spring MVC 注解驱动(注册 HandlerMapping、HandlerAdapter 等)
@ComponentScan(basePackages = "com.example", includeFilters = {
    @ComponentScan.Filter(type = org.springframework.context.annotation.FilterType.ANNOTATION, value = Controller.class)
})
public class WebConfig {
    // 配置视图解析器、静态资源处理等 MVC 组件
}
注解配置与 web.xml 的对应关系
注解配置方法 对应 web.xml 配置 作用
getRootConfigClasses() <context-param> + ContextLoaderListener 加载业务层配置,创建根容器
getServletConfigClasses() <servlet>init-param 加载 MVC 层配置,创建子容器
getServletMappings() <servlet-mapping> 配置 DispatcherServlet 映射路径

3. 静态资源处理问题与解决方案

url-pattern 配置为 / 时,DispatcherServlet 会拦截所有请求(包括静态资源如 .js.css、图片),但它仅处理动态请求,无法解析静态资源,导致 404 错误。需通过以下两种方式解决:

方案 1:mvc:default-servlet-handler(XML 配置)
<!-- springmvc.xml 中配置 -->
<!-- 1. 让未映射的请求交给容器默认 Servlet 处理(静态资源) -->
<mvc:default-servlet-handler default-servlet-name="default"/> <!-- Tomcat 默认 Servlet 名为 "default" -->

<!-- 2. 必须配合 <mvc:annotation-driven>,否则 @RequestMapping 映射会失效 -->
<mvc:annotation-driven/>
方案 2:mvc:resources(细粒度控制)
<!-- 映射 /static/** 路径到 classpath:/static/ 目录(如 /static/js/xxx.js → 实际路径 resources/static/js/xxx.js) -->
<mvc:resources mapping="/static/**" location="classpath:/static/" cache-period="31536000"/> <!-- 缓存 1 年 -->
<mvc:resources mapping="/images/**" location="/WEB-INF/images/" cache-period="31536000"/>
核心原理
  • mvc:default-servlet-handler:注册 DefaultServletHttpRequestHandler,将未匹配 @RequestMapping 的请求(如静态资源)转发给容器默认 Servlet;
  • mvc:annotation-driven:注册 RequestMappingHandlerMappingRequestMappingHandlerAdapter 等核心组件,修复 mvc:default-servlet-handler 导致的 @RequestMapping 失效问题。

DispatcherServlet 初始化流程(源码解析)

DispatcherServlet 的初始化本质是 Servlet 生命周期的 init() 方法,通过继承链(DispatcherServlet → FrameworkServlet → HttpServletBean → HttpServlet)完成上下文创建、策略组件初始化等工作。

1. 继承链与初始化入口

DispatcherServlet 的继承关系决定了初始化流程的调用顺序:

DispatcherServlet结构

// 继承链:DispatcherServlet → FrameworkServlet → HttpServletBean → HttpServlet
public class DispatcherServlet extends FrameworkServlet { ... }
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { ... }
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { ... }

初始化入口是 HttpServletBeaninit() 方法(Servlet 容器调用),最终触发 DispatcherServletinitStrategies() 方法,初始化所有核心策略组件。

2. 核心初始化流程(源码拆解)

DispatcherServlet处理过程

步骤 1:HttpServletBean#init () —— 初始化参数注入
public final void init() throws ServletException {
    // 1. 提取 web.xml 中的 init-param(如 contextConfigLocation)
    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
        try {
            // 2. 将 init-param 注入到 DispatcherServlet(通过 Spring BeanWrapper 实现属性注入)
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            bw.registerCustomEditor(Resource.class, new ResourceEditor(new ServletContextResourceLoader(getServletContext()), getEnvironment()));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        } catch (BeansException ex) {
            throw ex;
        }
    }

    // 3. 调用子类(FrameworkServlet)的 initServletBean(),继续初始化
    initServletBean();
}
步骤 2:FrameworkServlet#initServletBean () —— 创建 Web 上下文
protected final void initServletBean() throws ServletException {
    // 1. 初始化 WebApplicationContext(MVC 子容器)
    this.webApplicationContext = initWebApplicationContext();
    // 2. 空实现,供子类扩展
    initFrameworkServlet();
}

// 核心:创建并配置 WebApplicationContext
protected WebApplicationContext initWebApplicationContext() {
    // 1. 获取根容器(由 ContextLoaderListener 创建,业务层 Bean)
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    // 2. 若子容器已存在(如构造器注入),直接使用
    if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) {
                // 3. 设置父容器(根容器),并刷新上下文
                cwac.setParent(rootContext);
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }

    // 4. 若子容器不存在,查找或创建
    if (wac == null) {
        wac = findWebApplicationContext(); // 从 ServletContext 查找
    }
    if (wac == null) {
        wac = createWebApplicationContext(rootContext); // 新建子容器(默认 XmlWebApplicationContext)
    }

    // 5. 触发 DispatcherServlet 的 onRefresh(),初始化策略组件
    if (!this.refreshEventReceived) {
        onRefresh(wac);
    }

    // 6. 将子容器存入 ServletContext,供后续获取
    if (this.publishContext) {
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}
步骤 3:DispatcherServlet#onRefresh () —— 初始化策略组件

onRefresh() 是 DispatcherServlet 初始化的核心,通过 initStrategies() 注册 9 个核心策略组件(如 HandlerMapping、HandlerAdapter),若未手动配置则使用默认实现(读取 DispatcherServlet.properties):

@Override
protected void onRefresh(ApplicationContext context) {
    // 初始化所有策略组件
    initStrategies(context);
}

// 初始化 9 个核心策略组件
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);       // 1. 文件上传解析器(处理 multipart/form-data)
    initLocaleResolver(context);          // 2. 国际化解析器(处理多语言)
    initThemeResolver(context);           // 3. 主题解析器(处理网页主题)
    initHandlerMappings(context);         // 4. 处理器映射器(URL → Handler)
    initHandlerAdapters(context);         // 5. 处理器适配器(适配 Handler 调用)
    initHandlerExceptionResolvers(context); // 6. 异常解析器(处理 Handler 抛出的异常)
    initRequestToViewNameTranslator(context); // 7. 视图名转换器(无视图时自动生成视图名)
    initViewResolvers(context);           // 8. 视图解析器(逻辑视图名 → 实际视图)
    initFlashMapManager(context);         // 9. FlashMap 管理器(重定向时传递参数)
}
步骤 4:默认组件配置(DispatcherServlet.properties)

若未手动配置上述组件,Spring 会读取 org/springframework/web/servlet/DispatcherServlet.properties 中的默认实现:

# 国际化解析器(默认:根据请求头 Accept-Language 解析)
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

# HandlerMapping(默认:BeanName 映射 + 注解映射)
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

# HandlerAdapter(默认:支持 HttpRequestHandler、Controller、注解方法)
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

# 视图解析器(默认:JSP 视图解析器)
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

DispatcherServlet 请求处理流程(源码解析)

当 HTTP 请求到达 DispatcherServlet 后,通过 doGet()/doPost() 最终调用 doDispatch() 方法,完成 “请求接收→Handler 查找→拦截器执行→Handler 调用→视图渲染” 的全流程。

1. 核心流程入口:doDispatch ()

doDispatch处理

doDispatch() 是请求处理的 “总指挥”,代码逻辑虽长,但可拆解为 7 个关键步骤:

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; // 存储 Handler 返回的模型和视图
        Exception dispatchException = null;

        try {
            // ---------------------- 步骤1:处理文件上传请求 ----------------------
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // ---------------------- 步骤2:查找匹配的 HandlerExecutionChain ----------------------
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response); // 无匹配 Handler,返回 404
                return;
            }

            // ---------------------- 步骤3:查找匹配的 HandlerAdapter ----------------------
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // ---------------------- 步骤4:处理 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; // 资源未修改,返回 304
                }
            }

            // ---------------------- 步骤5:执行拦截器 preHandle()(正序) ----------------------
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return; // 若有拦截器返回 false,终止流程
            }

            // ---------------------- 步骤6:调用 Handler 处理业务逻辑 ----------------------
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            // ---------------------- 步骤7:异步处理判断 ----------------------
            if (asyncManager.isConcurrentHandlingStarted()) {
                return; // 异步处理已启动,无需后续渲染
            }

            // ---------------------- 步骤8:补全默认视图名 ----------------------
            applyDefaultViewName(processedRequest, mv);

            // ---------------------- 步骤9:执行拦截器 postHandle()(反序) ----------------------
            mappedHandler.applyPostHandle(processedRequest, response, mv);

        } catch (Exception ex) {
            dispatchException = ex; // 捕获 Handler 抛出的异常
        } catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }

        // ---------------------- 步骤10:处理结果(视图渲染/异常处理) ----------------------
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

    } catch (Exception ex) {
        // ---------------------- 步骤11:异常时执行拦截器 afterCompletion() ----------------------
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    } catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    } finally {
        // ---------------------- 步骤12:清理资源 ----------------------
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else {
            // 清理文件上传资源
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

2. 关键步骤详解

(1)步骤 2:getHandler () —— 查找匹配的 Handler

通过遍历 handlerMappings(如 RequestMappingHandlerMapping),根据请求 URL 匹配对应的 Handler(通常是 HandlerMethod,封装 Controller 方法),并封装为 HandlerExecutionChain(包含 Handler 和拦截器):

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    for (HandlerMapping hm : this.handlerMappings) {
        HandlerExecutionChain handler = hm.getHandler(request);
        if (handler != null) {
            return handler;
        }
    }
    return null;
}

RequestMappingHandlerMapping 为例,会根据 @RequestMapping 注解的 valuemethod 等属性匹配请求,返回对应的 HandlerMethod(如 UserController.getUserList() 方法)。

(2)步骤 3:getHandlerAdapter () —— 查找匹配的 HandlerAdapter

HandlerAdapter 是 “适配器”,解决 “DispatcherServlet 如何调用不同类型 Handler” 的问题。通过遍历 handlerAdapters,找到支持当前 Handler 类型的适配器(如 RequestMappingHandlerAdapter 适配 HandlerMethod):

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    for (HandlerAdapter ha : this.handlerAdapters) {
        if (ha.supports(handler)) {
            return ha;
        }
    }
    throw new ServletException("No adapter for handler [" + handler + "]");
}
(3)步骤 5/9:拦截器执行(preHandle → postHandle → afterCompletion)

HandlerExecutionChain 中的拦截器按以下顺序执行:

  • preHandle():Handler 执行前调用,正序执行(配置顺序 1→2→3),返回 false 则终止流程;
  • postHandle():Handler 执行后、视图渲染前调用,反序执行(3→2→1),可修改 ModelAndView
  • afterCompletion():视图渲染后调用,反序执行(3→2→1),用于释放资源(如关闭流),无论是否异常都会执行。

核心代码(applyPreHandle):

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null); // 执行已通过拦截器的 afterCompletion
                return false;
            }
            this.interceptorIndex = i; // 记录最后一个通过的拦截器索引
        }
    }
    return true;
}
(4)步骤 6:ha.handle () —— 调用 Handler 业务逻辑

通过 HandlerAdapter 调用 Handler 的核心方法(如 Controller 方法),以 RequestMappingHandlerAdapter 为例,会完成参数绑定、数据校验、方法反射调用等工作:

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ModelAndView mav;
    checkRequest(request);

    // 调用 Controller 方法(invokeHandlerMethod 是核心)
    if (this.synchronizeOnSession) {
        // 会话同步处理(可选)
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    } else {
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    return mav;
}

invokeHandlerMethod() 会通过反射调用 Controller 方法,并返回 ModelAndView(封装模型数据和逻辑视图名)。

(5)步骤 10:processDispatchResult () —— 视图渲染与异常处理
  • 正常流程:若 ModelAndView 不为空,调用 render() 方法渲染视图(如 JSP 解析、Thymeleaf 模板填充);
  • 异常流程:若存在 dispatchException,调用 processHandlerException() 处理异常(通过 HandlerExceptionResolver 生成错误视图)。

核心代码:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

    boolean errorView = false;

    // 1. 处理异常,生成错误视图
    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        } else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // 2. 渲染视图
    if (mv != null && !mv.wasCleared()) {
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }

    // 3. 执行拦截器 afterCompletion()
    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

DispatcherServlet 核心职责总结

DispatcherServlet 作为 Spring MVC 的 “大脑”,核心职责可概括为 “初始化策略组件 + 统一调度请求”

  1. 初始化阶段
    • 创建 Web 子容器,关联根容器(业务层 Bean);
    • 初始化 9 个核心策略组件(HandlerMapping、HandlerAdapter 等),支持灵活扩展。
  2. 请求处理阶段
    • 接收所有 HTTP 请求,统一入口;
    • 查找匹配的 Handler 和拦截器;
    • 执行拦截器的 preHandle 方法;
    • 调用 Handler 处理业务逻辑;
    • 执行拦截器的 postHandle 方法;
    • 渲染视图或处理异常;
    • 执行拦截器的 afterCompletion 方法,清理资源。
  3. 解耦与扩展
    • 通过策略模式(如不同的 HandlerMapping、ViewResolver)支持灵活扩展;
    • 隔离组件依赖,各组件专注于单一职责(URL 映射、参数绑定、视图渲染)。

关键问题与最佳实践

1. 为什么 url-pattern 配置为 / 而非 /*

  • /*:拦截所有请求(包括 .jsp),而 JSP 由 Tomcat 的 JspServlet 处理,DispatcherServlet 无法解析 JSP,导致 404;
  • /:拦截所有未被其他 Servlet 匹配的请求(不包括 .jsp),符合 MVC 处理动态请求、容器处理静态资源的分工。

2. 父子容器的关系与作用?

  • 根容器:由 ContextLoaderListener 创建,管理 Service、Dao 等业务层 Bean;
  • 子容器:由 DispatcherServlet 创建,管理 Controller、HandlerMapping 等 Web 层 Bean;
  • 访问规则:子容器可访问根容器的 Bean(如 Controller 注入 Service),根容器不可访问子容器的 Bean(解耦业务层与 Web 层)。

3. 如何自定义策略组件?

只需在 Spring 配置中注册自定义组件(如自定义 HandlerMapping),DispatcherServlet 会优先使用手动配置的组件,而非默认实现:

// 自定义 HandlerMapping
@Bean
public HandlerMapping customHandlerMapping() {
    BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
    mapping.setOrder(Ordered.HIGHEST_PRECEDENCE); // 优先使用
    return mapping;
}

总结

DispatcherServlet 是 Spring MVC 的核心,通过 “统一入口 + 策略模式” 实现了组件解耦与灵活扩展。理解其初始化流程(策略组件注册)和请求处理流程(Handler 查找→拦截器执行→视图渲染),是掌握 Spring MVC 底层逻辑的关键。无论是传统 web.xml 配置还是现代注解配置,其核心职责始终是协调各组件完成请求处理,为开发者提供低耦合、高扩展的 Web 开发框架