Spring Context 详细介绍
Spring Context(应用上下文)是 Spring Framework 的核心容器实现,提供了完整的应用运行时环境 ,是构建 Spring 应用的基石。它继承自 BeanFactory 并扩展了企业级特性,是 Spring IoC 容器的高级形态。
一、核心概念与定位
1. ApplicationContext 接口
java
public interface ApplicationContext extends
EnvironmentCapable, // 环境抽象
ListableBeanFactory, // 可列举的Bean工厂
HierarchicalBeanFactory, // 支持父子层级
MessageSource, // 国际化
ApplicationEventPublisher, // 事件发布
ResourcePatternResolver // 资源模式解析
{
// 获取应用名称、启动时间等
String getApplicationName();
long getStartupDate();
}
2. 与 BeanFactory 的关键区别
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 资源占用 | 轻量级,按需加载 | 完整功能,启动时加载 |
| 自动注册 | 需手动注册后处理器 | 自动 注册 BeanPostProcessor |
| 国际化 | 不支持 | 支持 MessageSource |
| 事件机制 | 不支持 | 支持 ApplicationEvent |
| 资源加载 | 基本支持 | 支持通配符模式加载 |
| 环境抽象 | 无 | 支持 Profile 和 PropertySource |
二、Context 类型体系
1. 常用实现类
基于注解配置(现代主流):
-
AnnotationConfigApplicationContext- 用于独立应用或单元测试
- 通过
@Configuration类加载 Bean - 示例:
new AnnotationConfigApplicationContext(AppConfig.class)
-
AnnotationConfigWebApplicationContext- 用于 Web 应用(Servlet 环境)
- 与
DispatcherServlet集成 - Spring Boot 默认使用的实现
基于 XML 配置(传统):
-
ClassPathXmlApplicationContext- 从类路径加载 XML 配置
- 示例:
new ClassPathXmlApplicationContext("app-context.xml")
-
FileSystemXmlApplicationContext- 从文件系统加载 XML 配置
Web 环境专用:
-
XmlWebApplicationContext- 基于 XML 的 Web 应用上下文
-
GenericWebApplicationContext- 通用 Web 上下文,支持多种配置方式
2. Spring Boot 专属
ConfigurableApplicationContext- 可配置的通用接口
SpringApplication.run()返回此类型
三、核心功能详解
1. Bean 容器管理
java
// 获取 Bean 实例
UserService userService = context.getBean(UserService.class);
// 检查 Bean 是否存在
boolean exists = context.containsBean("userService");
// 获取 Bean 定义名称
String[] beanNames = context.getBeanDefinitionNames();
// 获取特定注解的 Bean
Map<String, Object> beans = context.getBeansWithAnnotation(Service.class);
2. 环境抽象 (Environment)
java
// 获取当前激活的 Profile
String[] profiles = context.getEnvironment().getActiveProfiles();
// 获取系统属性
String javaVersion = context.getEnvironment().getProperty("java.version");
// 获取配置属性(优先级:系统属性 > 环境变量 > 配置文件)
String appName = context.getEnvironment().getProperty("app.name");
3. 资源加载 (ResourceLoader)
java
// 加载类路径资源
Resource resource = context.getResource("classpath:config.properties");
// 加载文件系统资源
Resource file = context.getResource("file:/opt/app/config.xml");
// 加载 URL 资源
Resource url = context.getResource("https://example.com/config.json");
// 使用通配符加载多个资源
Resource[] resources = context.getResources("classpath*:mappers/*.xml");
4. 国际化支持 (MessageSource)
java
// 配置 MessageSource Bean
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasenames("messages/messages", "messages/errors");
source.setDefaultEncoding("UTF-8");
return source;
}
// 使用方式
String message = context.getMessage("user.login.success",
new Object[]{"张三"}, Locale.CHINA);
5. 事件发布机制
java
// 定义事件
public class UserRegisteredEvent extends ApplicationEvent {
private final User user;
// 构造函数和 getter
}
// 发布事件
context.publishEvent(new UserRegisteredEvent(this, user));
// 监听事件(多种方式)
@Component
public class EmailNotificationListener {
@EventListener
public void handleUserRegistration(UserRegisteredEvent event) {
// 发送欢迎邮件
}
}
四、Context 配置与初始化
1. XML 配置方式(传统)
xml
<!-- app-context.xml -->
<beans xmlns="...">
<!-- 组件扫描 -->
<context:component-scan base-package="com.example"/>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb"/>
</bean>
<!-- 导入其他配置文件 -->
<import resource="classpath:dao-context.xml"/>
</beans>
// Java 代码初始化
ApplicationContext context = new ClassPathXmlApplicationContext(
"app-context.xml", "service-context.xml");
2. 注解配置方式(推荐)
java
@Configuration
@ComponentScan(basePackages = "com.example")
@Import({DataSourceConfig.class, SecurityConfig.class})
@PropertySource("classpath:app.properties")
public class AppConfig {
@Autowired
private Environment env;
@Bean
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl(env.getProperty("db.url"));
return ds;
}
}
// 初始化
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
3. 混合配置方式
java
@Configuration
@ImportResource("classpath:legacy-beans.xml") // 导入 XML 配置
public class HybridConfig {
// 新的注解配置 Bean
}
五、Context 生命周期
1. 创建与刷新流程
java
// 源码简化流程
public void refresh() {
// 1. 刷新前的准备
prepareRefresh();
// 2. 创建并刷新 BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备 BeanFactory(注册环境变量、资源加载器等)
prepareBeanFactory(beanFactory);
// 4. 调用 BeanFactoryPostProcessor(如 @Configuration 处理)
invokeBeanFactoryPostProcessors(beanFactory);
// 5. 注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 6. 初始化 MessageSource
initMessageSource();
// 7. 初始化应用事件多播器
initApplicationEventMulticaster();
// 8. 初始化特定 Context 的 Bean
onRefresh();
// 9. 注册监听器
registerListeners();
// 10. 实例化所有剩余的单例 Bean
finishBeanFactoryInitialization(beanFactory);
// 11. 完成刷新(发布 ContextRefreshedEvent)
finishRefresh();
}
2. 关闭流程
java
// 优雅关闭
((ConfigurableApplicationContext) context).close();
// 或注册 JVM 钩子
((ConfigurableApplicationContext) context).registerShutdownHook();
关闭时执行:
- 发布
ContextClosedEvent - 调用所有
@PreDestroy方法 - 销毁单例 Bean
- 关闭底层资源(DataSource、线程池等)
六、高级特性
1. Profile 机制(多环境支持)
java
@Configuration
public class AppConfig {
@Bean
@Profile("dev") // 仅在 dev 环境生效
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder().build();
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
HikariDataSource ds = new HikariDataSource();
// 生产环境配置
return ds;
}
}
// 激活 Profile 的方式
// 1. 代码设置
context.getEnvironment().setActiveProfiles("dev", "test");
// 2. 系统属性
-Dspring.profiles.active=prod
// 3. Spring Boot 配置文件
spring.profiles.active=prod
2. PropertySource 抽象(配置优先级)
优先级从高到低:
1. ServletConfig 初始化参数
2. ServletContext 初始化参数
3. JNDI 属性(java:comp/env/)
4. 系统属性(System.getProperties())
5. 环境变量
6. RandomValuePropertySource(random.*)
7. Jar 包外的配置文件(application-{profile}.properties)
8. Jar 包内的配置文件
9. @PropertySource 注解
10. 默认属性(SpringApplication.setDefaultProperties)
3. 条件化装配
java
@Configuration
public class ConditionalConfig {
@Bean
@ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
public DataSource mysqlDataSource() {
return new MysqlDataSource();
}
@Bean
@ConditionalOnMissingBean
public DefaultService defaultService() {
// 仅当没有 Service Bean 时创建
return new DefaultService();
}
}
4. 父子 Context 结构
java
// 父 Context(共享的 Service、Repository)
ApplicationContext parent = new AnnotationConfigApplicationContext(RootConfig.class);
// 子 Context(独立的 Web 层)
AnnotationConfigWebApplicationContext child = new AnnotationConfigWebApplicationContext();
child.setParent(parent);
child.register(WebConfig.class);
child.refresh();
// 子 Context 可访问父 Context 的 Bean,反之不行
典型应用场景:
- Spring MVC:
DispatcherServletContext(子)与ContextLoaderListenerContext(父) - 微服务:共享基础设施 Bean,隔离业务 Bean
七、Spring Boot 中的 ApplicationContext
1. 自动创建过程
java
// SpringApplication.run() 内部流程
public ConfigurableApplicationContext run(String... args) {
// 1. 创建 ApplicationContext(根据 classpath 推断类型)
context = createApplicationContext();
// 2. 注册核心 Bean 和初始化器
prepareContext(context);
// 3. 刷新 Context(调用 refresh())
refreshContext(context);
// 4. 调用 Runner(CommandLineRunner、ApplicationRunner)
callRunners(context, args);
return context;
}
// Context 类型推断规则
// - WebFlux 存在 -> AnnotationConfigReactiveWebServerApplicationContext
// - MVC 存在 -> AnnotationConfigServletWebServerApplicationContext
// - 非 Web -> AnnotationConfigApplicationContext
2. 核心增强
java
// 自动配置类
@AutoConfiguration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
public class DataSourceAutoConfiguration {
// 自动配置 DataSource Bean
}
// 所有自动配置类通过 spring.factories 加载
八、最佳实践
1. Context 组织策略
java
// 单体应用
ApplicationContext ctx = SpringApplication.run(AppConfig.class, args);
// 多模块应用
@Configuration
@Import({
PersistenceConfig.class,
ServiceConfig.class,
WebConfig.class,
SecurityConfig.class
})
public class ModularAppConfig { }
2. 资源管理
java
// 推荐:try-with-resources 自动关闭
try (AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class)) {
UserService service = ctx.getBean(UserService.class);
service.doSomething();
}
3. 性能优化
- 延迟刷新 :非必要不调用
refresh() - 索引扫描 :使用
@Indexed加速组件扫描(Spring 5+) - 懒加载 :
@Lazy延迟初始化非关键 Bean
4. 故障排查
java
// 打印所有 Bean 定义
Arrays.stream(context.getBeanDefinitionNames())
.sorted()
.forEach(System.out::println);
// 查看 Bean 详细信息
System.out.println(context.getBeanFactory().getBeanDefinition("userService"));
// 检查 Profile 和属性
System.out.println("Active profiles: " +
Arrays.toString(context.getEnvironment().getActiveProfiles()));
九、总结
Spring Context 是 Spring 应用的运行时环境总控,其价值体现在:
- 统一抽象:将配置、Bean、资源、环境统一管理
- 声明式编程:通过注解和配置驱动应用行为
- 生态整合:连接各个 Spring 模块的桥梁
- 生命周期管理:从启动到销毁的完整管控
- 可观测性:事件、Profile、属性源等提供运行时洞察
理解 ApplicationContext 的内部机制,是掌握 Spring 高级特性和排查复杂问题的关键。在现代 Spring Boot 应用中,虽然多数配置被自动化,但其核心原理和扩展点依然具有重要实践价值。