Skip to main content

1.4 Application Startup & Internals

← Back to Chapter 1: Spring & Spring Boot Fundamentals

Understanding the internal execution pathway of SpringApplication.run() is critical for debugging startup failures, optimizing boot latency, and writing enterprise initialization hooks.


Anatomy of @SpringBootApplication​

Every standard Spring Boot application starts with an annotated entry class:

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

The @SpringBootApplication annotation is a composite meta-annotation that bundles three critical annotations:

@SpringBootConfiguration // Specialization of @Configuration for Spring Boot
@EnableAutoConfiguration // Triggers auto-configuration imports & condition checks
@ComponentScan // Scans current package & sub-packages for @Component, @Service, etc.
public @interface SpringBootApplication { ... }

@SpringBootConfiguration​

This identifies the class as a Spring Boot configuration class.

It is essentially a specialized form of:

@Configuration

It tells Spring that this class can provide configuration for the application.

@EnableAutoConfiguration​

This enables Spring Boot's auto-configuration mechanism.

It tells Spring Boot:

Look at the dependencies and environment and configure appropriate components automatically.

@ComponentScan​

This tells Spring where to look for Spring components.

For example:

@Service
@Component
@Repository
@Controller
@RestController

Spring scans the appropriate packages and registers these classes as beans.

Critical Rule: Always position the @SpringBootApplication main class in the root package (e.g., com.example.myapp). Because @ComponentScan scans sub-packages hierarchically, placing it in a child package prevents Spring from discovering sibling packages.


Spring Boot application start Flow​

When SpringApplication.run() executes, it transitions through well-defined chronological phases:

main()
↓
SpringApplication.run()
↓
Create Spring Application Context
↓
Read configuration
↓
Perform component scanning
↓
Perform auto-configuration
↓
Create Spring Beans
↓
Inject dependencies
↓
Start embedded server
↓
Application ready

Detailed Explanation

1. Start Stopwatch & Listeners
└── Instantiates SpringApplicationRunListeners and fires ApplicationStartingEvent
2. Environment Preparation
└── Loads system properties, OS environment variables, application.yml/properties
└── Fires ApplicationEnvironmentPreparedEvent
3. Banner Printing
└── Prints ASCII banner to console or log file
4. ApplicationContext Creation
└── Instantiates AnnotationConfigServletWebServerApplicationContext (for Servlet apps)
5. Context Preparation & Post-Processing
└── Applies ApplicationContextInitializers, loads bean definitions
└── Fires ApplicationPreparedEvent
6. Context Refresh (The Heavy Lifting)
└── Instantiates singletons, configures embedded Tomcat, starts HTTP listener socket
7. Runners Execution
└── Invokes all CommandLineRunner and ApplicationRunner beans
8. Application Ready
└── Fires ApplicationReadyEvent; application is officially live!

What is Embedded Tomcat?​

Traditionally, Java web applications often required an externally installed application server.

Spring Boot commonly uses an embedded server.

For example:

Your Spring Boot JAR
|
├── Application code
├── Dependencies
└── Embedded server

You can run:

java -jar application.jar

and the application starts.

No separate Tomcat installation is normally required for a typical Spring Boot web application.

What is application.properties?​

This file is used to configure your Spring Boot application.

Example:

server.port=8081
spring.application.name=customer-service

Instead of hardcoding configuration inside Java code, we can keep it externally configurable.

For example:

@Value("${server.port}")
private int port;

Although for larger configuration groups, @ConfigurationProperties is often preferable.

application.properties vs application.yml​

Both are used for configuration.

Properties

server.port=8081
spring.application.name=customer-service

YAML

server:
port: 8081

spring:
application:
name: customer-service

YAML is often easier to read when configuration is deeply nested.