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.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Demystifying Spring Boot Startup: A Deep Dive into SpringApplication.run()

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentSpring Bootrun methodSpringApplicationapplication startup
Code Ape Tech Column
Written by

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

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.