Home About Me

Inside the Spring Boot 2.1.7 Startup Sequence

A Spring Boot 2.1.7 startup is a sequence of preparation steps, not a single leap from main to a running server. SpringApplication gathers initializers and listeners, builds an environment, creates the right application context, refreshes it, and then hands control to runners. The order matters because each stage supplies something the next stage expects.

Before run(): building the SpringApplication object

When SpringApplication is instantiated, it already performs four tasks:

  • infers the web application type (webApplicationType)
  • loads and instantiates ApplicationContextInitializer classes. It calls ClassLoader.getResources for META-INF/spring.factories, finds entries keyed by ApplicationContextInitializer.class, and creates instances
  • reads the same META-INF/spring.factories and instantiates ApplicationListener classes under the ApplicationListener.class key
  • infers the class containing the main method.

The run() sequence

SpringApplication.run() then drives startup.

Listeners and environment

  1. getRunListeners() reads every configured SpringApplicationRunListener from META-INF/spring.factories and constructs a SpringApplicationRunListeners instance.
  2. All run listeners receive starting(), and ApplicationStartedEvent is published.
  3. prepareEnvironment() prepares the environment: - inside it, getOrCreateEnvironment() returns a ConfigurableEnvironment; if none exists, it creates a StandardServletEnvironment. - configureEnvironment() configures active profiles, taking them from system environment variables or profiles added through SpringApplication.setAdditionalProfiles(""). - all run listeners receive environmentPrepared(), and ApplicationEnvironmentPreparedEvent is published. This is the point where configuration files such as application.properties are loaded.
  4. The banner is printed.
  5. createApplicationContext() creates an ApplicationContext according to webApplicationType. For SERVLET, it creates an AnnotationConfigServletWebServerApplicationContext.

That context constructor creates an AnnotatedBeanDefinitionReader, which checks whether the following objects need to be placed into the Spring context:

// User configuration classes. Implements BeanDefinitionRegistryPostProcessor.
// During container refresh, the post-processor scans Spring and registers beans.
ConfigurationClassPostProcessor
// Configures the Autowired annotation. Implements MergedBeanDefinitionPostProcessor.
AutowiredAnnotationBeanPostProcessor
// Configures the Required annotation. Implements MergedBeanDefinitionPostProcessor.
RequiredAnnotationBeanPostProcessor
// Configures JSR-250 annotations. Implements InstantiationAwareBeanPostProcessor.
CommonAnnotationBeanPostProcessor
// Configures JPA annotations.
PersistenceAnnotationBeanPostProcessor
// Configures the EventListener annotation. Implements SmartInitializingSingleton.
EventListenerMethodProcessor
// EventListener factory.
DefaultEventListenerFactory

Preparing the context

  1. prepareContext() prepares the application context: - context.setEnvironment(environment) assigns the environment to the ApplicationContext. - postProcessApplicationContext(context) configures the ResourceLoader and ClassLoader properties. - applyInitializers(context) takes the ApplicationContextInitializer subclasses found earlier and calls initialize() on each. - all run listeners receive contextPrepared(), and ApplicationContextInitializedEvent is published.

Refreshing the context

  1. refreshContext() refreshes the context. Underneath, it calls AbstractApplicationContext.refresh(), which proceeds through these steps:
  2. prepareRefresh() prepares the context for refresh.
  3. obtainFreshBeanFactory() initializes the BeanFactory.
  4. prepareBeanFactory(beanFactory) fills the BeanFactory with various capabilities.
  5. postProcessBeanFactory(beanFactory) adds post-processors. When Tomcat is being created, this post-processor is used to initialize the Tomcat Server class.
  6. invokeBeanFactoryPostProcessors(beanFactory) activates the various BeanFactory processors. The main work here is done by ConfigurationClassPostProcessor, which was injected through AnnotatedBeanDefinitionReader, to handle component injection.
  7. registerBeanPostProcessors(beanFactory) registers the BeanPostProcessors that intercept bean creation. This is only registration; they are actually called when beans are obtained.
  8. initMessageSource() initializes the context message source for internationalization. If the container does not have one, it creates a DelegatingMessageSource, and registers it in the Spring container.
  9. initApplicationEventMulticaster() initializes the application event multicaster and puts it in the applicationEventMulticaster bean. If the container does not have one, it creates a SimpleApplicationEventMulticaster event dispatcher and registers it in the Spring container.
  10. onRefresh() is left to subclasses to initialize other beans, mainly embedded servers such as Tomcat. ServletWebServerApplicationContext implements onRefresh() from AbstractApplicationContext, and its underlying method calls createWebServer() to create the WebServer container.
  11. registerListeners() finds listener beans among the registered beans and registers them with the event multicaster.
  12. finishBeanFactoryInitialization(beanFactory) initializes the remaining non-lazy singletons.
  13. finishRefresh() completes the refresh process, notifies the lifecycle processor lifecycleProcessor, and sends a ContextRefreshEvent to notify others.

  14. afterRefresh() is called.

  15. All run listeners receive started().
  16. callRunners() runs runners: it finds ApplicationRunner or CommandLineRunner beans in the IoC container and executes their run methods. This is the hook to use when application-specific logic must run at startup.
  17. All run listeners receive running().