Skip to content

DispatcherServlet

Spring MVC 与许多其他 Web 框架一样,是围绕 前端控制器(Front Controller) 模式设计的。在这种模式下,一个名为 DispatcherServlet 的中央 Servlet 为请求处理提供了一套共享算法,而实际的工作则由可配置的委托组件(Delegate Components)执行。这种模型非常灵活,支持多样化的工作流。

与任何 Servlet 一样,DispatcherServlet 需要根据 Servlet 规范进行声明和映射,可以使用 Java 配置或在 web.xml 中配置。反过来,DispatcherServlet 使用 Spring 配置来发现它所需要的委托组件,用于请求映射、视图解析、异常处理等。

Java 配置示例

以下 Java 配置示例注册并初始化了 DispatcherServlet,它会被 Servlet 容器自动检测。

java
public class MyWebApplicationInitializer implements WebApplicationInitializer {

	@Override
	public void onStartup(ServletContext servletContext) {

		// 加载 Spring Web 应用程序配置
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		context.register(AppConfig.class);

		// 创建并注册 DispatcherServlet
		DispatcherServlet servlet = new DispatcherServlet(context);
		ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
		registration.setLoadOnStartup(1);
		registration.addMapping("/app/*");
	}
}
kotlin
class MyWebApplicationInitializer : WebApplicationInitializer {

	override fun onStartup(servletContext: ServletContext) {

		// 加载 Spring Web 应用程序配置
		val context = AnnotationConfigWebApplicationContext()
		context.register(AppConfig::class.java)

		// 创建并注册 DispatcherServlet
		val servlet = DispatcherServlet(context)
		val registration = servletContext.addServlet("app", servlet)
		registration.setLoadOnStartup(1)
		registration.addMapping("/app/*")
	}
}

提示

除了直接使用 ServletContext API,你还可以扩展 AbstractAnnotationConfigDispatcherServletInitializer 并重写特定方法。

XML 配置示例 (web.xml)

以下 web.xml 配置示例注册并初始化了 DispatcherServlet

xml
<web-app>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/app-context.xml</param-value>
	</context-param>

	<servlet>
		<servlet-name>app</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value></param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>app</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>

</web-app>

注意

Spring Boot 遵循不同的初始化序列。Spring Boot 不再挂钩到 Servlet 容器的生命周期,而是使用 Spring 配置来引导自身和嵌入式 Servlet 容器。Spring 配置中检测到的 FilterServlet 声明会被注册到 Servlet 容器中。


补充教学

1. 为什么叫控制反转的“前端控制器”?

在没有 Spring MVC 之前,每一个 URL 可能都要对应一个独立的 Servlet(比如 UserServlet, OrderServlet)。这会导致大量的重复代码(如处理解析参数、权限校验)。 DispatcherServlet 的出现改变了这一点:它是唯一的入口。它负责接收所有请求,然后像一个“调度员”一样,根据你写的 @RequestMapping 注解,把请求分发给具体的 Java 方法。这就是典型的控制反转在 Web 层的体现。

2. 传统配置方式 vs Spring Boot

在传统的项目中(如上面的示例),你需要手动打成 WAR 包 并部署到外置的 Tomcat 中。在这个过程中,WebApplicationInitializerweb.xml 是连接 Tomcat 和 Spring 的桥梁。

而在 Spring Boot 中,流程是反过来的:

  • Spring Boot 先启动(main 方法执行)。
  • 它自动检测你的依赖(看到有 web 模块)。
  • 它自动在内部启动一个嵌入式 Tomcat
  • 它自动把 DispatcherServlet 注册进去。 这就是为什么你在 Spring Boot 中基本看不到上面的配置代码,但 DispatcherServlet 依然在幕后辛勤工作。

3. 理解 load-on-startup

在上面的配置中,我们看到了 registration.setLoadOnStartup(1)<load-on-startup>1</load-on-startup>

  • 默认行为:Servlet 通常是在第一次被访问时才实例化的(懒加载)。
  • 设置为 1 的作用:强制 Servlet 容器在应用启动时就立即创建并初始化 DispatcherServlet。这对于 Spring 来说非常重要,因为 DispatcherServlet 的初始化过程包括了扫描 Bean、建立映射表等耗时操作。通过这种方式,可以显著提升用户第一次访问时的响应速度。

Based on Spring Framework.