Spring MVC容器初始化核心是区分根上下文(加载Service/DAO等)与MVC上下文(加载@Controller等),通过web.xml配置ContextLoaderListener和DispatcherServlet,或用WebApplicationInitializer接口实现Java配置,二者均确保DispatcherServlet为根上下文的子容器以实现依赖单向注入。

Spring MVC 的容器上下文初始化,核心在于区分 根应用上下文(Root Context) 和 MVC 上下文(Servlet Context)。web.xml 是传统 XML 方式,WebApplicationInitializer 是 Servlet 3.0+ 的 Java 配置方式,二者目标一致:注册 DispatcherServlet 并为其配置对应的 WebApplicationContext。
web.xml 方式:显式声明 ContextLoaderListener 和 DispatcherServlet
这是最经典的方式,适用于 Servlet 容器(如 Tomcat)且未完全迁移到纯 Java 配置的项目。
-
ContextLoaderListener 负责加载根上下文(通常放 service、dao、数据源等非 Web 层 Bean),通过
contextConfigLocation指定配置文件(如applicationContext.xml) -
DispatcherServlet 负责加载 MVC 上下文(放 @Controller、@RequestMapping、ViewResolver 等 Web 相关 Bean),其
contextConfigLocation可指定spring-mvc.xml,也可留空让 Spring 自动扫描带@Configuration的类 - DispatcherServlet 的
load-on-startup设为 1,确保早于其他 Servlet 初始化
示例片段:
<!-- 根上下文 --><listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- MVC 上下文 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath: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>
WebApplicationInitializer 方式:用 Java 代码替代 web.xml
Servlet 3.0+ 容器支持,Spring 提供了 WebApplicationInitializer 接口(常继承 AbstractAnnotationConfigDispatcherServletInitializer),适合纯注解驱动项目。
立即学习“Java免费学习笔记(深入)”;
-
getRootConfigClasses()返回根上下文的 Java 配置类(如AppConfig.class),对应原 ContextLoaderListener -
getServletConfigClasses()返回 MVC 上下文的配置类(如WebConfig.class),对应 DispatcherServlet 的 context -
getServletMappings()指定 DispatcherServlet 的 URL 映射(如"/") - 无需 web.xml,容器启动时自动发现并执行该初始化器
典型实现:
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{AppConfig.class}; // service, dao, datasource
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class}; // @Controller, ViewResolver, etc.
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
关键细节:两个上下文的关系与隔离
DispatcherServlet 持有的 WebApplicationContext 是根上下文的子容器 —— 它能访问根容器中的 Bean(如 Service),但根容器无法访问 MVC 容器中的 Bean(如 Controller)。这种设计保障了分层清晰和依赖单向性。
- 若在
@Controller中注入@Service,只要 Service 在根上下文中定义,就能成功注入 - 不要在根配置类中扫描
@Controller;也不要在 Web 配置类中重复定义数据源或事务管理器 - 使用
@ComponentScan时注意 basePackages 区分,例如:
根配置类:@ComponentScan("com.example.service")
Web 配置类:@ComponentScan("com.example.web")
现代简化:Spring Boot 下的隐式初始化
虽然问题聚焦传统 Spring MVC,但值得提一句:Spring Boot 默认不使用 web.xml 或手动写 WebApplicationInitializer。它通过 SpringServletContainerInitializer + 自动配置机制,在内嵌容器启动时自动注册 DispatcherServlet,并按约定加载 @SpringBootApplication 类作为根上下文,同时启用 WebMvcAutoConfiguration 构建 MVC 环境。开发者只需关注 @Configuration 类和组件扫描即可。


















