在 Spring MVC 应用中,理解 RootApplicationContext
和 WebApplicationContext
这两个应用上下文(Application Context)的区别和关系,是掌握 Spring MVC 架构的关键。它们共同构成了 Spring Web 应用的 IoC 容器层次结构。
Spring MVC 应用通常包含不同类型的组件:
将这两类组件分离到不同的上下文中,可以实现:
RootApplicationContext
中的业务 Bean 可以被多个 WebApplicationContext
(如不同的 Servlet)共享。CCTV.PCFANGYUANKOU.COM37丨JRS.XUANYAJU.CN50丨FOOTBALL.HASUNSOFT.COM52丨OUGUAN.HECHENGTAOLI.COM81
ONLINE.GDYFDGC.CN68丨SWEET.RUNAIBIOTECH.COM29丨JRS.GCYMGS.CN90丨ONLINE.IPASC.CN19
NBA.FJDDSD.COM11丨XIJIA.BRANDAGRI.COM33丨LIVE.CHANGTAI333.COM71丨ZHIBO.FUWANG1688.COM21
MOBI.JNSDPMJ.COM97丨YES.SANGONGZY.COM20丨CCTV.GYZXSJ.COM83丨SHARE.YMLYTZ.COM42
ONLINE.BOTIANQI.COM52丨ZUQIU.BTJZ.NET.CN56丨FOOTBALL.0518XZW.COM45丨GDYFDGC.CN85
M.DFYXBJ.CN14丨ONLINE.SZ-EDC.COM28丨L.FQW.INFO80丨VIP.TCCQLXS.CN18
ZHIBO.HZBESTSEO.COM37丨SHARE.HZTENGHONG.COM72丨ZB.XINGJIJIN.ORG.CN48丨MOBI.SNQCZ.COM27
VIP.FJFYW.NET68丨BOLL.XIANGHETL.COM15丨TV.FMMITV.COM46丨CCTV.CQPXY.COM97
QQ.HAXFDC.COM77丨SJB.HZSMC.COM89丨WEIBO.DIJIUXIAOXUE.COM74丨IQIYI.SZ-EDC.COM19
WAP.FJFYW.NET42丨MAP.AIIN.ORG.CN38丨ZHIBO.HBST123.COM58丨JRS.GZBYJULEBU.COM53
M.RSEYEPRO.COM51丨ZHIBO8.SEO-YUN.COM10丨SHARE.BOTIANQI.COM83丨IQIYI.KEYUQZJX.COM71
VIP.HASUNSOFT.COM25丨SAISHI.GDYFDGC.CN99丨SINA.YCYKJ.NET87丨ZB.HZBESTSEO.COM91
@Service
注解的 Service 类@Repository
注解的 DAO/Repository 类DataSource
)PlatformTransactionManager
)EntityManagerFactory
)ContextLoaderListener
加载,配置文件如 applicationContext.xml
或 Java 配置类。RootApplicationContext
的所有 Bean。@Controller
和 @RestController
注解的控制器HandlerMapping
(处理请求映射)HandlerAdapter
(调用处理器)ViewResolver
(解析视图名称)MultipartResolver
(处理文件上传)HandlerExceptionResolver
(处理异常)LocaleResolver
(处理国际化)ThemeResolver
(处理主题)DispatcherServlet
创建和管理。一个应用可以有多个 DispatcherServlet
,每个都有自己的 WebApplicationContext
。DispatcherServlet
加载,配置文件如 [servlet-name]-servlet.xml
或通过 @EnableWebMvc
的 Java 配置。 +-------------------------+
| RootApplicationContext |
| (父上下文) |
| - Service Beans |
| - Repository Beans |
| - DataSource |
| - TransactionManager |
+------------+------------+
|
| 继承 (可访问)
v
+-------------------------+
| WebApplicationContext |
| (子上下文) |
| - Controller Beans |
| - ViewResolver |
| - HandlerMapping |
| - ... |
+-------------------------+
Controller
可以直接 @Autowired
Service
。Service
无法直接访问 ViewResolver
或 Controller
。<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 1. 配置 ContextLoaderListener (创建 RootApplicationContext) -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 指定 RootApplicationContext 的配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
<!--
也可以使用多个文件:
<param-value>
/WEB-INF/applicationContext.xml,
/WEB-INF/security-context.xml
</param-value>
-->
</context-param>
<!-- 2. 配置 DispatcherServlet (创建 WebApplicationContext) -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
DispatcherServlet 默认会加载 [servlet-name]-servlet.xml
这里明确指定配置文件位置
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.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>
</web-app>
<!-- /WEB-INF/applicationContext.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 扫描 Service 和 Repository 组件 -->
<context:component-scan base-package="com.example.service, com.example.repository" />
<!-- 数据源配置 (示例) -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<!-- JdbcTemplate (可选) -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 启用注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
<!-- /WEB-INF/dispatcher-servlet.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描 Controller 组件 -->
<context:component-scan base-package="com.example.controller" />
<!-- 启用 Spring MVC 注解驱动 -->
<!-- 等价于配置了 DefaultAnnotationHandlerMapping,
AnnotationMethodHandlerAdapter 等核心组件 -->
<mvc:annotation-driven />
<!-- 配置视图解析器 (例如 JSP) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 处理静态资源 (CSS, JS, Images) -->
<mvc:resources location="/static/" mapping="/static/**" />
</beans>
// com/example/config/WebAppInitializer.java
package com.example.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 1. 创建 Root WebApplicationContext
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfig.class); // 注册 Root 配置类
// 2. 将 Root Context 添加为 ServletContext 的监听器
servletContext.addListener(new ContextLoaderListener(rootContext));
// 3. 创建 DispatcherServlet 的 WebApplicationContext
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebConfig.class); // 注册 Web 配置类
// 4. 注册 DispatcherServlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
// com/example/config/RootConfig.java
package com.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan(
basePackages = "com.example",
// 排除 @Controller, @RestController, @EnableWebMvc 的类
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = {org.springframework.stereotype.Controller.class, EnableWebMvc.class}
)
)
public class RootConfig {
// 数据源、事务、Service、Repository 等配置
}
// com/example/config/WebConfig.java
package com.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc // 启用 Spring MVC 配置
@ComponentScan(basePackages = "com.example.controller") // 只扫描 Controller
public class WebConfig implements WebMvcConfigurer {
// 配置视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
// 其他 MVC 配置...
}
你可以在 Controller
中注入 ApplicationContext
来验证继承关系:
java深色版本@RestController
public class TestController {
@Autowired
private ApplicationContext webApplicationContext; // 这是 WebApplicationContext
@GetMapping("/context-test")
public String testContext() {
// 获取父上下文
ApplicationContext parentContext = webApplicationContext.getParent();
if (parentContext != null) {
return "Web Context 父上下文存在,Bean 数量: " + parentContext.getBeanDefinitionCount();
} else {
return "Web Context 没有父上下文!";
}
}
}
特性 | RootApplicationContext | WebApplicationContext |
---|---|---|
角色 | 父上下文 (Parent Context) | 子上下文 (Child Context) |
创建者 | ContextLoaderListener | DispatcherServlet |
主要职责 | 管理业务层、数据层组件 (Service, Repository, DataSource, TransactionManager) | 管理 Web 层组件 (Controller, ViewResolver, HandlerMapping) |
可访问性 | 不能 访问 WebApplicationContext 中的 Bean | 可以 访问 RootApplicationContext 中的所有 Bean |
配置文件 | contextConfigLocation 参数指定 (如 applicationContext.xml) | [servlet-name]-servlet.xml 或 DispatcherServlet 的 contextConfigLocation |
配置类 | @Configuration 类被 ContextLoaderListener 加载 | @Configuration 类被 DispatcherServlet 加载,通常带有 @EnableWebMvc |
推荐扫描包 | com.example.service, com.example.repository | com.example.controller |
核心要点:
WebApplicationContext
继承 RootApplicationContext
,实现了依赖注入的传递性。@Configuration
) 和 WebApplicationInitializer
,而非 XML。理解这两个上下文,是构建结构清晰、易于维护的大型 Spring MVC 应用的基础。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。