乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 SpringMVC概述与DispatcherServlet

    • 本章导读:Spring MVC概述与DispatcherServlet
    • Spring MVC 是什么
    • MVC 设计模式
    • 前端控制器模式
    • DispatcherServlet
    • 核心组件协作
  • 第2章 控制器与请求映射

    • 本章导读:控制器与请求映射
    • Controller
    • RestController
    • RequestMapping
    • GetMapping
    • PostMapping
    • PutMapping
    • DeleteMapping
    • PathVariable
    • RESTful
    • 请求映射原理
  • 第3章 请求参数获取与转换

    • 本章导读:请求参数获取与转换
    • RequestParam
    • RequestBody
    • RequestHeader
    • CookieValue
    • Model
    • ModelAttribute
    • 数据绑定原理
    • 数据校验
  • 第4章 响应数据与视图解析

    • 本章导读:响应数据与视图解析
    • ResponseBody
    • ResponseEntity
    • ModelAndView
    • ViewResolver
    • HttpMessageConverter
    • forward与redirect
  • 第5章 拦截器过滤器与跨域

    • 本章导读:拦截器、过滤器与跨域
    • HandlerInterceptor
    • WebMvcConfigurer
    • CrossOrigin
    • 登录验证实战
  • 第6章 文件上传与异常处理

    • 本章导读:文件上传与异常处理
    • MultipartFile
    • 文件下载
    • ExceptionHandler
    • ControllerAdvice
    • RestControllerAdvice
    • ResponseStatus
  • 第7章 高级特性与最佳实践

    • 本章导读:高级特性与最佳实践
    • SessionAttributes
    • SessionAttribute
    • RedirectAttributes
    • MockMvc测试
    • 国际化
    • 最佳实践
  • 第8章 扩展与异步机制

    • 本章导读:扩展与异步机制
    • 异步请求处理
    • 自定义参数解析器
    • 内容协商

DispatcherServlet

本章是 Spring MVC 教程的起点。Spring MVC 基于 Spring 容器运行,本教程默认必要的 Core 配置(组件扫描、依赖注入)已就绪,此后所有内容只聚焦 Web 请求处理层 的机制与注解。

DispatcherServlet 是 Spring MVC 的前端控制器(Front Controller),也是整个 Web 请求处理链路的唯一入口。理解它如何接收请求、如何分发、如何协调各组件,是掌握 Spring MVC 的根基。


定义与作用

DispatcherServlet 是前端控制器模式在 Spring MVC 中的具体实现。它之所以存在,是因为传统 Servlet 开发中每个 URL 对应一个独立 Servlet 的做法导致了代码重复和配置膨胀——每个 Servlet 都要手动处理编码、认证、日志,每增加一个接口就要在 web.xml 增加一对 servlet-mapping。DispatcherServlet 用一个中央入口替代了 N 个分散入口,将通用逻辑集中到一处,让业务处理器只关注业务本身。

DispatcherServlet 是 Spring MVC 的核心类,继承自 HttpServlet。它的职责可以用一句话概括:接收所有进入应用的 HTTP 请求,把它们分发给正确的处理器(Controller),并把处理结果包装成 HTTP 响应返回给客户端。

在传统的 Servlet 开发中,每个 URL 对应一个独立的 Servlet 类(如 /login 对应 LoginServlet,/register 对应 RegisterServlet)。Spring MVC 用 DispatcherServlet 彻底改变了这一模式——整个应用只需要一个 DispatcherServlet,它像一位"总调度员",根据请求的 URL 和方法,把请求转交给对应的 Controller 方法处理。

生活类比:医院挂号台

想象你去医院看病:

  • 传统 Servlet 模式:医院有 20 个科室,每个科室门口都有一个独立的挂号窗口。你要去骨科就去骨科窗口,要去内科就去内科窗口,每个窗口只办一件事。
  • DispatcherServlet 模式:医院只有一个总挂号台(DispatcherServlet)。你告诉挂号台"我要看骨科",挂号台查询科室分布表(HandlerMapping),找到骨科位置,给你一张导诊单(HandlerExecutionChain),你拿着单子去对应科室(Controller)看病。看完病后,报告单(ModelAndView)交回挂号台,挂号台帮你打印成正式报告(View渲染),最后交到你手里(HTTP响应)。

这个类比的关键在于:DispatcherServlet 不处理具体业务,它只负责"找到正确的人、把请求送过去、把结果包装好送回来"。


核心原理

请求处理完整流程

当一个 HTTP 请求到达 Spring MVC 应用时,DispatcherServlet 按以下步骤处理:

上图展示了 DispatcherServlet 的完整调度流程。注意其中 HandlerMapping、HandlerAdapter、ViewResolver 三个组件的分工——这种分工不是随意设计的,而是三种经典设计模式(策略模式、适配器模式、职责链模式)的具体体现。

上图展示了 Spring MVC 处理一个请求的完整链路。注意几个关键节点:

  1. HandlerMapping 负责"找对人"——根据 URL 找到对应的 Controller 方法
  2. HandlerAdapter 负责"能调用"——屏蔽不同 Controller 类型的调用差异
  3. 拦截器链 在 Controller 前后插入横切逻辑(如登录检查、日志记录)
  4. ViewResolver 负责"看得见"——把逻辑视图名解析为具体的页面模板

DispatcherServlet 的容器协作

DispatcherServlet 本身也是 Spring 容器中的一个 Bean。它通过容器获取所有协作组件:

重要边界:上图中的 Service、Repository、DataSource 等 Bean 也在容器中,但它们属于 Spring Core 层,本教程不展开。我们只需知道:Controller 通过依赖注入获取 Service,这条链路由容器自动完成。


适用位置与配置

DispatcherServlet 需要在 Web 应用中进行注册。Spring Boot 项目中,这一步被自动配置隐藏了;但在传统 Spring MVC 项目中,需要显式配置。

Spring Boot 自动配置(默认)

Spring Boot 会自动注册 DispatcherServlet,映射路径为 /(处理所有请求):

// 无需手动配置,Spring Boot 自动完成
// 等效于在 application.properties 中:
// server.servlet.context-path=/

传统 Spring MVC 配置(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>
配置项含义
servlet-classDispatcherServlet 的全限定类名
contextConfigLocationSpring MVC 配置文件的位置
load-on-startup服务器启动时立即加载(而非第一次请求时)
url-pattern/ 表示处理所有请求(静态资源除外)

完整示例

场景

飞翔科技开发了一个员工信息管理系统。CTO 大翔要求系统使用 Spring MVC 处理所有 Web 请求。架构师白歌负责搭建 DispatcherServlet 的基础配置。

项目结构

employee-web/
├── src/main/java/
│   └── com/feixiang/web/
│       ├── EmployeeController.java    # 控制器(本教程后续章节讲解)
│       └── config/
│           └── WebConfig.java         # Spring MVC 配置类
├── src/main/resources/
│   └── application.properties
└── pom.xml

Spring Boot 项目(零配置)

// EmployeeController.java
package com.feixiang.web;

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

@RestController
public class EmployeeController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Spring MVC!";
    }
}
# application.properties
server.port=8080

启动应用后,DispatcherServlet 自动注册,处理所有请求:

$ curl http://localhost:8080/hello
Hello from Spring MVC!

传统 Spring MVC 项目(显式配置)

// WebConfig.java
package com.feixiang.web.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan("com.feixiang.web")
public class WebConfig {
    // DispatcherServlet 需要的配置
}
// WebAppInitializer.java(替代 web.xml)
package com.feixiang.web.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null; // 父容器配置(本教程不展开)
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class}; // DispatcherServlet 容器配置
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"}; // 映射所有请求
    }
}

变化分析:

  • Spring Boot 模式下,DispatcherServlet 的注册和配置完全自动化,开发者只需写 Controller
  • 传统模式下,需要显式告诉 Spring"哪里是 DispatcherServlet 的配置类、映射什么路径"
  • 两种模式的请求处理流程完全一致,区别只在"谁负责注册 DispatcherServlet"

易错场景与面试考点

误区一:DispatcherServlet 处理所有请求,包括静态资源

错误认知:"DispatcherServlet 映射了 /,所以 /css/style.css 也会交给 Controller 处理。"

纠正:默认情况下确实如此。Spring Boot 通过 ResourceHttpRequestHandler 自动处理静态资源;传统 Spring MVC 需要在配置中显式配置静态资源映射:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**")
            .addResourceLocations("classpath:/static/");
}

否则访问 /css/style.css 会报 404,因为 DispatcherServlet 找不到对应的 Controller 方法。

误区二:DispatcherServlet 和 Servlet 容器是同一个东西

错误认知:"DispatcherServlet 就是 Tomcat,Tomcat 就是 DispatcherServlet。"

纠正:Tomcat 是 Servlet 容器,负责接收网络连接、解析 HTTP 协议、管理线程池。DispatcherServlet 是一个 Servlet,由 Tomcat 创建并调用其 service() 方法。关系是:Tomcat 调用 DispatcherServlet,DispatcherServlet 调用 Controller。两者是"容器"与"被容器管理的组件"的关系。

面试高频:DispatcherServlet 的工作流程

标准回答:

  1. 接收 HTTP 请求
  2. 通过 HandlerMapping 查找匹配的 Controller 方法
  3. 获取拦截器链(HandlerExecutionChain)
  4. 执行拦截器 preHandle
  5. 通过 HandlerAdapter 调用 Controller 方法
  6. 获取返回结果(ModelAndView 或数据)
  7. 执行拦截器 postHandle
  8. 通过 ViewResolver 解析视图(如果是视图渲染模式)
  9. 渲染视图
  10. 执行拦截器 afterCompletion
  11. 返回 HTTP 响应

小结

DispatcherServlet 是 Spring MVC 的前端控制器和唯一入口,它接收所有 HTTP 请求,通过 HandlerMapping 找到目标 Controller,通过 HandlerAdapter 执行方法,最后通过 ViewResolver 渲染响应。它不处理具体业务,只负责调度与协调。

本章与全局的关系:本章回答了"请求从哪来、怎么被分发"。下一章"控制器与请求映射"将深入讲解 Controller 如何声明请求映射规则,以及 @RequestMapping 等注解的用法。

上一页
前端控制器模式
下一页
核心组件协作