Spring Boot DispatcherServlet 自动配置源码深度解读
2026/9/19 3:15:28 网站建设 项目流程

版本说明:本文基于Spring Boot 3.x源码进行分析。Spring Boot 3.x 基于 Jakarta EE 9+,因此 Servlet API 包名为jakarta.servlet(而非早期版本中的javax.servlet)。

一、引言

在传统的 Spring MVC 开发中,开发者需要在web.xml中手动配置DispatcherServlet,指定其映射路径、加载配置文件等。而使用 Spring Boot 之后,只需引入spring-boot-starter-web依赖,DispatcherServlet便自动完成配置和注册,开发者可以直接编写 Controller 开始 Web 开发。

这一切的奥秘,就藏在DispatcherServletAutoConfiguration这个自动配置类中。本文将深入解读该类源码,剖析 Spring Boot 是如何在幕后完成DispatcherServlet的自动装配的。

二、类概述与定位

DispatcherServletAutoConfiguration位于org.springframework.boot.autoconfigure.web.servlet包下,是 Spring Boot 对 SpringDispatcherServlet的自动配置实现。该类适用于两种场景:

  1. 独立应用(Standalone Application):使用嵌入式 Web 服务器(如 Tomcat、Jetty、Undertow)的场景;
  2. 可部署应用(Deployable Application):使用SpringBootServletInitializer部署到外部容器的场景。
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@AutoConfiguration(after=ServletWebServerFactoryAutoConfiguration.class)@ConditionalOnWebApplication(type=Type.SERVLET)@ConditionalOnClass(DispatcherServlet.class)publicclassDispatcherServletAutoConfiguration{// ...}

2.1 核心注解解读

注解作用
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)指定该自动配置类拥有最高优先级,优先于其他自动配置执行
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)在 Web 服务器工厂自动配置之后执行,确保 Servlet 容器已就绪
@ConditionalOnWebApplication(type = Type.SERVLET)仅在Servlet 类型的 Web 应用中生效(区别于 Reactive Web)
@ConditionalOnClass(DispatcherServlet.class)仅当类路径中存在DispatcherServlet时才生效

2.2 两个关键常量

publicstaticfinalStringDEFAULT_DISPATCHER_SERVLET_BEAN_NAME="dispatcherServlet";publicstaticfinalStringDEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME="dispatcherServletRegistration";
  • DEFAULT_DISPATCHER_SERVLET_BEAN_NAMEDispatcherServlet实例在 Spring 容器中的 Bean 名称,默认为dispatcherServlet
  • DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAMEServletRegistrationBean在 Spring 容器中的 Bean 名称,用于向 Servlet 容器注册DispatcherServlet

三、DispatcherServletConfiguration — 创建 DispatcherServlet 实例

DispatcherServletAutoConfiguration内部定义了第一个静态内部配置类DispatcherServletConfiguration,负责创建DispatcherServlet的 Bean 实例。

@Configuration(proxyBeanMethods=false)@Conditional(DefaultDispatcherServletCondition.class)@ConditionalOnClass(ServletRegistration.class)@EnableConfigurationProperties(WebMvcProperties.class)protectedstaticclassDispatcherServletConfiguration{// ...}

3.1 条件注解分析

  • @Configuration(proxyBeanMethods = false):Spring Boot 2.2+ 引入的优化配置。当设为false时,Spring 不会为该配置类创建 CGLIB 代理,所有@Bean方法的调用将绕过容器的单例管理,每次调用都会执行方法体本身(而非从容器中返回已缓存的单例)。对于DispatcherServletAutoConfiguration这类轻量级配置类,关闭代理可以减少启动时的字节码生成开销,提升启动速度。
  • @Conditional(DefaultDispatcherServletCondition.class)自定义条件,判断是否需要创建默认的DispatcherServlet(下文详述);
  • @ConditionalOnClass(ServletRegistration.class):仅当ServletRegistration类存在时生效;
  • @EnableConfigurationProperties(WebMvcProperties.class):启用WebMvcProperties配置属性绑定,即spring.mvc前缀的配置项。

3.2 dispatcherServlet() 方法

@Bean(name=DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)publicDispatcherServletdispatcherServlet(WebMvcPropertieswebMvcProperties){DispatcherServletdispatcherServlet=newDispatcherServlet();dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());returndispatcherServlet;}

该方法创建一个DispatcherServlet实例,并从WebMvcProperties(即application.properties/application.yml中以spring.mvc开头的配置)中读取四个关键参数:

  • spring.mvc.dispatch-options-request:是否分发 OPTIONS 请求;
  • spring.mvc.dispatch-trace-request:是否分发 TRACE 请求;
  • spring.mvc.publish-request-handled-events:是否发布请求处理完成事件;
  • spring.mvc.log-request-details:是否记录请求详情(用于调试)。

3.3 multipartResolver() 方法

@Bean@ConditionalOnBean(MultipartResolver.class)@ConditionalOnMissingBean(name=DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)publicMultipartResolvermultipartResolver(MultipartResolverresolver){returnresolver;}

该方法的作用是检测并适配用户自定义的MultipartResolver

  • @ConditionalOnBean(MultipartResolver.class):仅当容器中已存在MultipartResolver类型的 Bean 时生效;
  • @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME):仅当不存在名为multipartResolver(即DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME的值)的 Bean 时生效。

设计意图:如果用户创建了MultipartResolver但命名不正确,Spring Boot 会自动将其"适配"为DispatcherServlet期望的标准名称multipartResolver

边界场景说明:需要注意的是,该方法的参数为MultipartResolver resolver(而非ObjectProvider<MultipartResolver>)。这意味着当容器中存在多个MultipartResolver类型的 Bean 时,Spring 在注入方法参数时可能抛出NoUniqueBeanDefinitionException@ConditionalOnBean(MultipartResolver.class)仅检查"至少存在一个",并未限制"恰好存在一个"。因此,如果用户自定义了多个MultipartResolverBean,需要配合@Primary@Qualifier指定优先级,以避免注入冲突。

四、DispatcherServletRegistrationConfiguration — 注册 DispatcherServlet

第二个内部静态配置类DispatcherServletRegistrationConfiguration负责将DispatcherServlet注册到 Servlet 容器中。

@Configuration(proxyBeanMethods=false)@Conditional(DispatcherServletRegistrationCondition.class)@ConditionalOnClass(ServletRegistration.class)@EnableConfigurationProperties(WebMvcProperties.class)@Import(DispatcherServletConfiguration.class)protectedstaticclassDispatcherServletRegistrationConfiguration{// ...}

注意@Import(DispatcherServletConfiguration.class):这意味着注册配置会导入创建配置,确保DispatcherServlet实例优先于注册 Bean 被创建。

4.1 dispatcherServletRegistration() 方法

@Bean(name=DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)@ConditionalOnBean(value=DispatcherServlet.class,name=DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)publicDispatcherServletRegistrationBeandispatcherServletRegistration(DispatcherServletdispatcherServlet,WebMvcPropertieswebMvcProperties,ObjectProvider<MultipartConfigElement>multipartConfig){DispatcherServletRegistrationBeanregistration=newDispatcherServletRegistrationBean(dispatcherServlet,webMvcProperties.getServlet().getPath());registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());multipartConfig.ifAvailable(registration::setMultipartConfig);returnregistration;}

该方法创建了一个DispatcherServletRegistrationBean,其关键逻辑包括:

  1. 映射路径:从WebMvcProperties中读取spring.mvc.servlet.path,默认为/(即处理所有请求);
  2. Servlet 名称:设置为dispatcherServlet
  3. 启动加载顺序:从spring.mvc.servlet.load-on-startup读取,默认值为-1(表示首次请求时初始化);
  4. 文件上传配置:如果容器中存在MultipartConfigElement,则自动注入,用于处理文件上传。

DispatcherServletRegistrationBeanServletRegistrationBean的子类,而ServletRegistrationBean实现了ServletContextInitializer接口。在 Spring Boot 启动过程中,所有ServletContextInitializer会被收集并执行,从而将DispatcherServlet真正注册到 Servlet 容器中。

五、自定义条件类深度解析

DispatcherServletAutoConfiguration中定义了两个自定义条件类,它们共同决定了自动配置是否生效。

5.1 DefaultDispatcherServletCondition

@Order(Ordered.LOWEST_PRECEDENCE-10)privatestaticfinalclassDefaultDispatcherServletConditionextendsSpringBootCondition{@OverridepublicConditionOutcomegetMatchOutcome(ConditionContextcontext,AnnotatedTypeMetadatametadata){// 核心判断逻辑}}

该条件的匹配逻辑如下:

场景结果原因
容器中已有名为dispatcherServletDispatcherServletBean不匹配用户已自定义,无需自动创建
容器中已有名为dispatcherServlet的非DispatcherServletBean不匹配名称冲突,避免覆盖用户定义
容器中不存在名为dispatcherServlet的 Bean,且不存在其他名称的DispatcherServletBean匹配需要自动创建
容器中有DispatcherServletBean,但名称都不是dispatcherServlet匹配存在其他名称的DispatcherServlet,但仍需创建默认名称的实例

上述四种场景覆盖了所有可能性,彼此之间构成完整的逻辑划分:

  • 第一、二行覆盖了"存在名为dispatcherServlet的 Bean"的所有情况(无论类型是否为DispatcherServlet),结果均为不匹配
  • 第三、四行覆盖了"不存在名为dispatcherServlet的 Bean"的所有情况(无论是否存在其他名称的DispatcherServlet),结果均为匹配

设计思想:该条件保证 Spring Boot不会覆盖用户自定义的DispatcherServlet,同时也兼顾了容器中可能存在多个DispatcherServlet实例的复杂场景。

5.2 DispatcherServletRegistrationCondition

该条件的匹配逻辑更为复杂,分为两步:

第一步:检查是否存在名为dispatcherServlet的 Bean(对应源码方法checkDefaultDispatcherName

该方法存在三种分支:

分支条件结果
分支 A容器中不存在名为dispatcherServlet的 Bean通过第一步检查,继续执行第二步checkServletRegistration()
分支 B存在名为dispatcherServlet的 Bean,但类型不是DispatcherServlet不匹配(防止错误注册)
分支 C存在名为dispatcherServlet的 Bean,且类型是DispatcherServlet通过第一步检查,继续执行第二步checkServletRegistration()(用户已自定义DispatcherServlet,但仍需检查是否需要自动注册)

需要特别说明的是,分支 A 和分支 C 返回"通过第一步检查"后,并不意味着整个条件已经匹配通过,代码会继续执行checkServletRegistration()方法进行第二步判断。两步都返回match时,DispatcherServletRegistrationConfiguration才会最终生效。

第二步:检查 ServletRegistrationBean 是否存在(对应源码方法checkServletRegistration

场景结果
没有任何ServletRegistrationBean,且没有名为dispatcherServletRegistration的 Bean匹配
存在名为dispatcherServletRegistrationServletRegistrationBean不匹配(用户已自定义)
存在名为dispatcherServletRegistration的非ServletRegistrationBean不匹配(名称冲突)
存在其他ServletRegistrationBean,但没有名为dispatcherServletRegistration匹配

设计思想:该条件保证注册过程同样尊重用户的自定义配置,避免自动注册与用户手动注册发生冲突。

六、总结

通过源码分析,我们可以总结出DispatcherServletAutoConfiguration的核心设计思想:

6.1 开箱即用,零配置启动

只需引入spring-boot-starter-webDispatcherServletAutoConfiguration便会自动创建并注册DispatcherServlet,映射到根路径/,开发者无需任何额外配置即可开始 Web 开发。

6.2 条件化控制,尊重用户配置

通过精心设计的条件注解和自定义条件类,Spring Boot 实现了“用户自定义优先”的策略:

  • 如果用户已经创建了DispatcherServlet,自动配置不会覆盖;
  • 如果用户已经注册了ServletRegistrationBean,自动配置不会重复注册。

6.3 职责分离,高内聚低耦合

将"创建实例"和"注册到容器"拆分为两个独立的配置类和两个独立的 Bean,使得每个步骤都可以被独立地条件化控制,也便于用户进行部分覆盖。

6.4 配置属性驱动,灵活可调

通过@EnableConfigurationProperties(WebMvcProperties.class),将spring.mvc.*配置项与DispatcherServlet的行为参数绑定,开发者可以通过配置文件灵活调整DispatcherServlet的各项行为,无需修改代码。


DispatcherServletAutoConfiguration是 Spring Boot 自动配置哲学的典范之作——它用简洁优雅的代码,实现了复杂而灵活的条件化自动装配,让开发者真正享受到"开箱即用"的便捷体验。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询