Demystifying Spring Boot Startup: A Deep Dive into SpringApplication.run()
This article provides a step‑by‑step technical analysis of Spring Boot's startup process, breaking down the creation of SpringApplication, the configuration of application type, initializers, listeners, and the eight phases executed by the run() method, complete with code snippets and diagrams.
Introduction
The author continues a series on Spring Boot by moving from basic usage to an in‑depth examination of the framework's core source code, focusing on the SpringApplication.run() workflow introduced in Spring Boot 2.4.0.
Source Version
The analysis targets Spring Boot 2.4.0; readers are advised to use the same version to avoid discrepancies.
Where to Start?
The entry point for a Spring Boot application is the class annotated with @SpringBootApplication that contains a public static void main(String[] args) method, for example:
@SpringBootApplication
public class AnnotationDemoApplication {
public static void main(String[] args) {
SpringApplication.run(AnnotationDemoApplication.class, args);
}
}Splitting the Source
The static run() method in SpringApplication delegates to two steps: creating a SpringApplication instance and invoking its run() method.
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}Creating SpringApplication
Construction of SpringApplication involves three phases (marked ②, ③, ④ in the source diagram): setting the application type, loading initializers, and loading listeners.
Setting Application Type
The type is determined by the WebApplicationType enum, which can be NONE, SERVLET, or REACTIVE. The decision is based on classpath detection (e.g., presence of DispatcherServlet indicates SERVLET).
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) &&
!ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) &&
!ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}Setting Initializer (ApplicationContextInitializer)
Initializers are loaded from META-INF/spring.factories. The framework reads the fully‑qualified class names and instantiates them before the IOC container refreshes.
Setting Listener (ApplicationListener)
Listeners are also defined in spring.factories. Spring Boot extends ApplicationEvent with SpringApplicationEvent to publish lifecycle events such as ApplicationStartingEvent, ApplicationEnvironmentPreparedEvent, etc.
Executing run() – The Eight Steps
1. Get and Start Run Listeners
Spring loads SpringApplicationRunListener implementations from spring.factories. The default is EventPublishingRunListener, which creates a SimpleApplicationEventMulticaster to broadcast events.
public interface SpringApplicationRunListener {
void starting();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);
}2. Environment Construction
The method prepareEnvironment loads system and user properties (e.g., application.properties) and publishes ApplicationEnvironmentPreparedEvent.
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);3. Create IOC Container
Based on the detected WebApplicationType, Spring creates an appropriate ApplicationContext (e.g., AnnotationConfigServletWebServerApplicationContext for servlet applications).
context = createApplicationContext();4. Pre‑process IOC Container
Spring calls prepareContext, which loads the primary source class into the bean definition map, applies all ApplicationContextInitializer instances, and publishes ApplicationContextInitializedEvent and ApplicationPreparedEvent.
5. Refresh Container
The refresh process executes the full Spring container lifecycle: bean factory preparation, post‑processor invocation, bean post‑processor registration, message source initialization, event multicaster setup, and finally publishing ContextRefreshedEvent.
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}6. Post‑process IOC Container
Hook method afterRefresh can be overridden for custom actions; the default implementation does nothing.
afterRefresh(context, applicationArguments);7. Publish End‑of‑Run Event
After the container is refreshed, EventPublishingRunListener broadcasts ApplicationStartedEvent using the application context’s own event publisher.
8. Execute Runners
Spring Boot invokes all CommandLineRunner and ApplicationRunner beans via callRunners, allowing custom code to run after the application is fully started.
callRunners(context, applicationArguments);Summary
The Spring Boot startup sequence can be understood as eight distinct phases, each responsible for setting up the environment, creating and configuring the IOC container, broadcasting lifecycle events, and finally running user‑defined runners. Mastering these steps helps developers debug and extend the boot process effectively.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
