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 配置中检测到的 Filter 和 Servlet 声明会被注册到 Servlet 容器中。


补充教学 ​

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

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

2. 传统配置方式 vs Spring Boot ​

在传统的项目中(如上面的示例),你需要手动打成 WAR 包 并部署到外置的 Tomcat 中。在这个过程中,WebApplicationInitializer 或 web.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.