您的位置:

深入理解Spring Boot启动顺序

一、Spring Boot启动流程

在了解Spring Boot的启动顺序之前,我们需要先了解Spring Boot的启动流程。在Spring Boot启动时,会以SpringApplication为入口进行启动。SpringApplication会开启一些基本的事件(ApplicationEvent),并将这些事件发送给所有注册了相应监听器(ApplicationListener)的组件进行处理。

因此,Spring Boot的启动流程可以概括为以下几步:

  1. 创建SpringApplication
  2. 执行SpringApplication的run()方法
  3. SpringApplication会依次发布以下事件:ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent、ApplicationFailedEvent
  4. 所有注册了相应的监听器会处理它们感兴趣的事件

二、Spring Boot启动顺序

1. SpringApplication构造函数

在创建SpringApplication实例的时候,Spring Boot会进行相关的初始化和准备阶段。在这个过程中,Spring Boot会根据一些默认设置来决定要使用哪些特性,并对这些特性进行配置。比如,自动配置、Profile、配置文件等。

示例代码

@SpringBootApplication
public class SpringApplicationDemo {
  public static void main(String[] args) {
    SpringApplication application = new SpringApplication(SpringApplicationDemo.class);
    application.run(args);
  }
}

2. ApplicationStartingEvent

在调用SpringApplication的run()方法之前,SpringApplication会发布ApplicationStartingEvent事件。这个事件表示SpringApplication即将启动。在这个事件中,我们可以进行一些相关的操作,比如输出程序启动日志。

示例代码

@Component
public class StartingEventListener implements ApplicationListener<ApplicationStartingEvent> {
  private static final Logger LOGGER = LoggerFactory.getLogger(StartingEventListener.class);

  @Override
  public void onApplicationEvent(ApplicationStartingEvent event) {
    LOGGER.info("Application is starting with args: {}",
        Arrays.toString(event.getArgs()));
  }
}

3. ApplicationEnvironmentPreparedEvent

在执行run()方法之前,SpringApplication会发布ApplicationEnvironmentPreparedEvent事件。在这个事件中,我们可以对应用程序的环境进行一些自定义配置,比如添加自定义属性、配置环境变量等。

示例代码

@Component
public class EnvironmentPreparedEventListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
  @Override
  public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    ConfigurableEnvironment environment = event.getEnvironment();
    Map<String, Object> properties = new HashMap<>();
    properties.put("server.port", 8081);
    PropertiesPropertySource propertySource = new PropertiesPropertySource("customProperties", properties);
    environment.getPropertySources().addFirst(propertySource);
  }
}

4. ApplicationContextInitializedEvent

在执行run()方法时,Spring Boot会发布ApplicationContextInitializedEvent事件。这个事件表示ApplicationContext正在被创建,但是还没有加载任何Bean。在这个事件中,我们可以手动往ApplicationContext中添加一些Bean。

示例代码

@Component
public class ContextInitializedEventListener implements ApplicationListener<ApplicationContextInitializedEvent> {
  @Override
  public void onApplicationEvent(ApplicationContextInitializedEvent event) {
    ConfigurableApplicationContext context = event.getApplicationContext();
    context.getBeanFactory().registerSingleton("myBean", new Object());
  }
}

5. ApplicationPreparedEvent

在上一步中,ApplicationContext成功创建并加载了所有的Bean。在执行run()方法之前,Spring Boot会发布ApplicationPreparedEvent事件。在这个事件中,我们可以获取ApplicationContext,并进行一些自定义配置。

示例代码

@Component
public class PreparedEventListener implements ApplicationListener<ApplicationPreparedEvent> {
  @Override
  public void onApplicationEvent(ApplicationPreparedEvent event) {
    ConfigurableApplicationContext context = event.getApplicationContext();
    DataSource dataSource = context.getBean(DataSource.class);
    try {
      dataSource.getConnection().close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
}

6. ApplicationStartedEvent

在上一步结束后,ApplicationContext会被刷新,并启动完成。在这个时候,Spring Boot会发布ApplicationStartedEvent事件。在这个事件中,我们可以进行一些启动后的操作,比如数据初始化。

示例代码

@Component
public class StartedEventListener implements ApplicationListener<ApplicationStartedEvent> {
  private static final Logger LOGGER = LoggerFactory.getLogger(StartedEventListener.class);

  @Override
  public void onApplicationEvent(ApplicationStartedEvent event) {
    LOGGER.info("Application has started...");
  }
}

7. ApplicationReadyEvent

当应用程序启动并且ApplicationContext中的Bean都已经装配好之后,Spring Boot会发布ApplicationReadyEvent事件,这个事件表示此时应用程序已经准备好了。我们可以在这种情况下进行一些定时任务的启动、消息的处理等操作。

示例代码

@Component
public class ReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {
  @Override
  public void onApplicationEvent(ApplicationReadyEvent event) {
    TimerTask task = new TimerTask() {
      @Override
      public void run() {
        System.out.println("I'm a TimerTask!");
      }
    };
    Timer timer = new Timer();
    timer.schedule(task, 5000L);
  }
}

8. ApplicationFailedEvent

如果应用程序启动失败,Spring Boot会发布ApplicationFailedEvent事件,这个事件表示应用程序启动过程中出现了错误。在这个事件中我们可以获取到失败的原因,并进行相应的处理。

示例代码

@Component
public class FailedEventListener implements ApplicationListener<ApplicationFailedEvent> {
  @Override
  public void onApplicationEvent(ApplicationFailedEvent event) {
    Throwable throwable = event.getException();
    LOGGER.error("Application failed to start: {}", throwable.getMessage());
  }
}

三、总结

通过本文的介绍,我们可以详细了解Spring Boot启动顺序背后的机制和原理。在实际开发中,我们可以根据自己的需求选择合适的时间点进行自定义操作,从而达到更加优美的应用启动顺序。