为什么既要 web.xml 又要 springmvc.xml?能不能只配一个?
一、先给结论
这两个文件不属于同一个层级,管的事情完全不同:
web.xml是 Servlet 容器的启动说明书,告诉 Tomcat"把哪些 Servlet、Filter 加载起来"。springmvc.xml是 Spring MVC 框架的内部配置,告诉 Spring"Controller 怎么扫描、视图怎么解析、静态资源怎么处理"。
它们的关系,类似"公司大门门禁登记 "和"部门内部规章制度":
- 没有大门登记,人进不来,部门制度再完善也没用。
- 没有部门制度,人进来了但不知道该干什么。
二、用公司类比理解两个文件
1. web.xml 是大楼物业的登记表
Tomcat 是这栋大楼的物业。它启动时,只认一份登记表------web.xml。
web.xml 告诉物业:
- 有哪些 Servlet 需要注册?比如
DispatcherServlet。 - 哪些 URL 交给这个 Servlet 处理?比如
/。 - 有哪些 Filter 需要安装?比如编码过滤器。
- 项目启动时加载哪个 Spring 配置文件?比如
classpath:springmvc.xml。
没有 web.xml,Tomcat 根本不知道 DispatcherServlet 的存在,请求连 Spring MVC 的门都进不了。
2. springmvc.xml 是 Spring MVC 部门的内部手册
DispatcherServlet 被 Tomcat 启动后,它需要知道自己怎么工作。这些信息写在 springmvc.xml 里:
- 扫描哪些包下的 Controller?
- 视图解析器的前缀后缀是什么?
- 静态资源
/static/**怎么处理? - 有没有拦截器、类型转换器、消息转换器?
- 根路径
/映射到哪个页面?
没有 springmvc.xml,DispatcherServlet 虽然启动了,但不知道有哪些 Controller,也不知道怎么渲染页面。
三、为什么不能合并成一个文件
1. 归属规范不同
| 文件 | 归属 | 谁读取 |
|---|---|---|
web.xml |
Servlet 规范 | Tomcat 等 Servlet 容器 |
springmvc.xml |
Spring 框架规范 | Spring 的 XmlWebApplicationContext |
Tomcat 不认识 Spring 的 <bean>、<context:component-scan>;Spring 也不负责 Servlet 的注册。两者的解析器完全不同,不能混在一个文件里。
2. 加载时机不同
Tomcat 启动
→ 读取 web.xml
→ 注册 Filter、Servlet
→ 创建 DispatcherServlet
→ DispatcherServlet 读取 springmvc.xml
→ 初始化 Spring 容器
→ 扫描 Controller、创建 Bean
→ 应用就绪
web.xml 在 Tomcat 启动阶段被读取,springmvc.xml 在 DispatcherServlet 初始化阶段被读取。先后顺序决定了它们不可能合并。
3. 职责不同
web.xml管"容器级别"的事:Servlet、Filter、Listener、Session 超时、欢迎页。springmvc.xml管"框架级别"的事:Bean 扫描、依赖注入、视图解析、异常处理、拦截器。
一个是物业,一个是部门,职责边界清晰。
四、能不能不配 web.xml?
能,但有前提。
Servlet 3.0 之后,规范提供了 Java Config 替代 web.xml。可以用代码注册 Servlet 和 Filter:
java
public class MyWebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
AnnotationConfigWebApplicationContext context =
new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration =
servletContext.addServlet("dispatcher", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
这样就不需要 web.xml 了。springmvc.xml 也可以被 Java 配置类替代:
java
@Configuration
@EnableWebMvc
@ComponentScan("com.xie.springmvc")
public class AppConfig implements WebMvcConfigurer {
// 视图解析器、静态资源、拦截器都在这里配置
}
Spring Boot 就是把这个过程完全自动化了:内嵌 Tomcat + 自动注册 DispatcherServlet + 自动配置 Spring MVC ,所以 Spring Boot 项目里既没有 web.xml,通常也没有 springmvc.xml。
五、能不能只配 springmvc.xml,不配 web.xml?
传统外置 Tomcat 部署方式下,不能。
因为外置 Tomcat 不认识 Spring 的配置文件,它只会读 web.xml 来决定加载哪些 Servlet。没有 web.xml,Tomcat 不会主动创建 DispatcherServlet,Spring MVC 根本没有入口。
除非满足以下条件之一:
| 条件 | 说明 |
|---|---|
使用 Servlet 3.0+ 的 WebApplicationInitializer |
用 Java 代码替代 web.xml |
| 使用 Spring Boot 内嵌容器 | 容器由 Spring Boot 启动,不需要 web.xml |
| 使用 ServletContainerInitializer(SPI) | 框架通过 SPI 自动注册 Servlet |
六、Spring Boot 为什么不需要这两个文件
Spring Boot 做了三件事:
- 内嵌 Tomcat:Tomcat 不再由外部启动,而是由 Spring Boot 应用自己启动。
- 自动注册 DispatcherServlet :
DispatcherServletAutoConfiguration自动创建并注册DispatcherServlet,映射到/。 - 自动配置 Spring MVC :
WebMvcAutoConfiguration自动配置视图解析器、静态资源、消息转换器,不需要手写springmvc.xml。
所以 Spring Boot 项目里,两个文件都消失了,配置被分散到 application.yml 和自动配置类中。
七、记忆方法
1. 一句话口诀
web.xml 管大门,springmvc.xml 管内部;
大门不登记,内部再完善也进不来。
2. 公司类比
Tomcat = 大楼物业
web.xml = 物业登记表(哪些公司入驻、门禁怎么装)
DispatcherServlet = 公司前台
springmvc.xml = 公司内部手册(部门怎么分工、流程怎么走)
3. 加载顺序口诀
Tomcat 先读 web.xml,
创建 DispatcherServlet,
DispatcherServlet 再读 springmvc.xml,
初始化 Spring 容器。
4. 能不能合并口诀
规范不同不能合,
时机不同不能合,
职责不同不能合。
5. 能不能不配口诀
Servlet 3.0 之后,web.xml 可以用 Java Config 替代;
Spring Boot 之后,两个都可以不配,自动配置全包了。
八、总结
| 问题 | 答案 |
|---|---|
| 为什么要有 web.xml | Tomcat 靠它注册 Servlet 和 Filter,是容器启动入口 |
| 为什么要有 springmvc.xml | DispatcherServlet 靠它知道怎么扫描 Controller、解析视图、处理静态资源 |
| 为什么不能合并 | 归属规范不同、加载时机不同、职责不同 |
| 能不能只配一个 | 传统外置 Tomcat 下不能;Servlet 3.0+ 可用 Java Config 替代 web.xml;Spring Boot 两者都可省 |
| Spring Boot 为什么不需要 | 内嵌容器 + 自动注册 DispatcherServlet + 自动配置 Spring MVC |
理解这两个文件的关键是分清"容器层 "和"框架层 "。web.xml 是容器层的入口,springmvc.xml 是框架层的配置。它们不是重复配置,而是各自负责不同阶段的事情。当容器由 Spring Boot 自己启动时,容器层和框架层被合并管理,两个文件自然就不需要了。