【Spring】Spring Context 详细介绍

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();

关闭时执行

  1. 发布 ContextClosedEvent
  2. 调用所有 @PreDestroy 方法
  3. 销毁单例 Bean
  4. 关闭底层资源(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:DispatcherServlet Context(子)与 ContextLoaderListener Context(父)
  • 微服务:共享基础设施 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 应用的运行时环境总控,其价值体现在:

  1. 统一抽象:将配置、Bean、资源、环境统一管理
  2. 声明式编程:通过注解和配置驱动应用行为
  3. 生态整合:连接各个 Spring 模块的桥梁
  4. 生命周期管理:从启动到销毁的完整管控
  5. 可观测性:事件、Profile、属性源等提供运行时洞察

理解 ApplicationContext 的内部机制,是掌握 Spring 高级特性和排查复杂问题的关键。在现代 Spring Boot 应用中,虽然多数配置被自动化,但其核心原理和扩展点依然具有重要实践价值。

相关推荐
风之子npu2 小时前
AMBA AXI - transaction order记录
后端·restful
Kiyra2 小时前
LinkedHashMap 源码阅读
java·开发语言·网络·人工智能·安全·阿里云·云计算
Clarence Liu2 小时前
虚拟机与容器的差异与取舍
linux·后端·容器
sheji34162 小时前
【开题答辩全过程】以 山林湖泊生态文明建设管控系统为例,包含答辩的问题和答案
java·spring boot
banpu2 小时前
Spring相关
数据库·spring·sqlserver
幽络源小助理2 小时前
SpringBoot兼职发布平台源码 | JavaWeb项目免费下载 – 幽络源
java·spring boot·后端
co松柏2 小时前
AI+Excalidraw,用自然语言画手绘风格技术图
前端·人工智能·后端
2501_916766542 小时前
【Java】HashMap集合实现类
java·开发语言
不会聊天真君6472 小时前
设计模式、线程状态、上下文切换、线程安全(JAVA并发第二期)
java