Spring Boot ApplicationContext刷新前的配置

深入解析Spring Boot启动过程中ApplicationContext刷新前的关键配置步骤和扩展点

ApplicationContext刷新概述

在Spring Boot启动过程中,ApplicationContext的刷新(通过refresh()方法)是核心步骤。但在刷新之前,Spring Boot会进行一系列准备工作:

public ConfigurableApplicationContext run(String... args) {
  // ...前置准备...
  prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  refreshContext(context); // 核心刷新方法
  // ...后置处理...
}

刷新前的配置阶段是开发者可以干预Spring Boot启动过程的关键点,通过多种扩展机制实现自定义配置。

刷新前的关键配置步骤
1

环境准备(Environment Preparation)

创建并配置环境对象,加载配置文件,发布环境准备事件。

private ConfigurableEnvironment prepareEnvironment(
    SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments) {

  // 创建环境对象
  ConfigurableEnvironment environment = getOrCreateEnvironment();

  // 配置环境(包括配置文件加载)
  configureEnvironment(environment, applicationArguments.getSourceArgs());

  // 发布环境准备事件
  listeners.environmentPrepared(environment);

  // 绑定环境到SpringApplication
  bindToSpringApplication(environment);

  return environment;
}
2

创建ApplicationContext

根据应用类型创建具体的ApplicationContext实例。

protected ConfigurableApplicationContext createApplicationContext() {
  Class<?> contextClass = this.applicationContextClass;
  if (contextClass == null) {
    try {
      // 根据应用类型选择Context实现
      switch (this.webApplicationType) {
        case SERVLET:
          contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
          break;
        case REACTIVE:
          contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
          break;
        default:
          contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
      }
    }
    catch (ClassNotFoundException ex) {
      // 异常处理
    }
  }
  return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
3

准备ApplicationContext

在刷新前对ApplicationContext进行配置。

private void prepareContext(ConfigurableApplicationContext context,
    ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments, Banner printedBanner) {

  // 设置环境
  context.setEnvironment(environment);

  // 应用后置处理
  postProcessApplicationContext(context);

  // 应用初始化器
  applyInitializers(context);

  // 触发contextPrepared事件
  listeners.contextPrepared(context);

  // 打印启动信息
  if (this.logStartupInfo) {
    logStartupInfo(context.getParent() == null);
    logStartupProfileInfo(context);
  }

  // 注册特定的单例Bean
  context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
  if (printedBanner != null) {
    context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
  }

  // 加载资源(配置源)
  Set<Object> sources = getAllSources();
  load(context, sources.toArray(new Object[0]));

  // 触发contextLoaded事件
  listeners.contextLoaded(context);
}
刷新前的扩展点
1

ApplicationContextInitializer

自定义初始化器可以在刷新前对ApplicationContext进行配置:

public class CustomInitializer
    implements ApplicationContextInitializer<ConfigurableApplicationContext> {

  @Override
  public void initialize(ConfigurableApplicationContext applicationContext) {
    // 添加自定义属性源
    ConfigurableEnvironment env = applicationContext.getEnvironment();
    Map<String, Object> customProperties = new HashMap<>();
    customProperties.put("custom.property", "value");
    env.getPropertySources().addFirst(
      new MapPropertySource("customProperties", customProperties));
  }
}
2

ApplicationListener

实现特定接口监听启动事件:

@Component
public class ApplicationContextPreparer
    implements ApplicationListener<ApplicationContextInitializedEvent> {

  @Override
  public void onApplicationEvent(ApplicationContextInitializedEvent event) {
    ConfigurableApplicationContext context = event.getApplicationContext();
    // 在上下文准备完成后但刷新前执行操作
    System.out.println("ApplicationContext prepared, about to refresh");
  }
}
关键概念

ApplicationContext

Spring的核心接口,提供Bean工厂、资源加载、事件发布等功能。

刷新过程

ApplicationContext初始化和配置的核心过程,包括Bean定义加载、Bean实例化等。

扩展点

  • ApplicationContextInitializer
  • BeanFactoryPostProcessor
  • ApplicationListener
  • EnvironmentPostProcessor

配置源

  • application.properties/yml
  • 环境变量
  • 命令行参数
  • 自定义PropertySource
最佳实践
使用初始化器添加配置

通过ApplicationContextInitializer添加自定义属性源或修改环境配置。

监听启动事件

实现ApplicationListener接口响应ApplicationContextInitializedEvent事件。

使用BeanFactoryPostProcessor

在Bean定义加载后、实例化前修改Bean定义。

启动流程示意图
1
创建SpringApplication
2
准备环境
3
创建ApplicationContext
4
准备上下文(本文重点)
5
刷新上下文

总结

ApplicationContext刷新前的配置阶段是Spring Boot启动过程中最灵活的部分,开发者可以通过多种方式影响容器的行为:

掌握这些扩展点可以帮助开发者更好地理解Spring Boot的启动机制,并实现更灵活的应用配置。