How SpringApplication Starts

The Startup Sequence

One line in main starts the whole application: SpringApplication.run(ShopEaseApplication.class, args). Behind it, Spring Boot runs a fixed sequence of steps. Knowing them helps you debug slow startups and "bean not found" errors.

SpringApplication.run(...)
   |
   1. Decide the app type (SERVLET / REACTIVE / NONE) from the classpath
   2. Load ApplicationContextInitializers and ApplicationListeners (META-INF/spring.factories)
   3. Prepare the Environment: application.yml, profiles, env vars, command-line args
   4. Print the banner
   5. Create the ApplicationContext (AnnotationConfigServletWebServerApplicationContext)
   6. Load bean definitions: your @Component classes + auto-configuration classes
   7. Refresh the context: create singletons, inject dependencies, run @PostConstruct
   8. Start the embedded web server (Tomcat on port 8080)
   9. Call CommandLineRunner / ApplicationRunner beans
  10. Publish ApplicationReadyEvent  ->  "Started ShopEaseApplication in 2.1 seconds"

Hooking Into Startup

@SpringBootApplication
public class ShopEaseApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(ShopEaseApplication.class);
        app.setBannerMode(Banner.Mode.OFF);            // customise before run
        app.run(args);
    }

    @Bean
    ApplicationRunner warmUp(ProductRepository products) {
        return args -> System.out.println("Products in DB: " + products.count());
    }

    @EventListener(ApplicationReadyEvent.class)
    void ready() {
        System.out.println("ShopEase is ready to take orders");
    }
}

Example

Run it and watch the log:

./mvnw spring-boot:run

Example output

INFO  o.s.b.w.e.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
INFO  o.s.b.w.e.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
INFO  c.s.ShopEaseApplication            : Started ShopEaseApplication in 2.134 seconds (process running for 2.51)
Products in DB: 42
ShopEase is ready to take orders

Simulating the Lifecycle in Plain Java

Example

A tiny "container" that runs the same phases in the same order. Real Spring is much bigger, but the order is identical:

import java.util.*;
import java.util.function.*;

public class Main {
    public static void main(String[] args) {
        MiniApp app = new MiniApp();
        app.register("productRepository", () -> new Bean("productRepository"));
        app.register("productService", () -> new Bean("productService"));
        app.addRunner(() -> System.out.println("CommandLineRunner: loading demo products"));
        app.run();
    }
}

class Bean {
    final String name;
    Bean(String name) { this.name = name; System.out.println("  create  " + name); }
    void postConstruct() { System.out.println("  init    " + name + " (@PostConstruct)"); }
}

class MiniApp {
    private final Map<String, Supplier<Bean>> definitions = new LinkedHashMap<>();
    private final List<Runnable> runners = new ArrayList<>();
    void register(String name, Supplier<Bean> s) { definitions.put(name, s); }
    void addRunner(Runnable r) { runners.add(r); }

    void run() {
        System.out.println("1. prepare environment (profile=dev)");
        System.out.println("2. load " + definitions.size() + " bean definitions");
        System.out.println("3. refresh context:");
        definitions.values().forEach(s -> s.get().postConstruct());
        System.out.println("4. start web server on port 8080");
        runners.forEach(Runnable::run);
        System.out.println("5. ApplicationReadyEvent published");
    }
}

Output

1. prepare environment (profile=dev)
2. load 2 bean definitions
3. refresh context:
  create  productRepository
  init    productRepository (@PostConstruct)
  create  productService
  init    productService (@PostConstruct)
4. start web server on port 8080
CommandLineRunner: loading demo products
5. ApplicationReadyEvent published

Practice

Exercise: Add a bean that prints "Cache warmed" after the application is fully ready (not during bean creation).

Show answer
@Component
class CacheWarmer {
    @EventListener(ApplicationReadyEvent.class)
    void warm() {
        System.out.println("Cache warmed");
    }
}