Spring Boot Startup Process
Demo Project
1. Application Entry Point
- The entry point for a Spring Boot application is typically a class annotated with
@SpringBootApplication
. - The
@SpringBootApplication
annotation is a combination of:-
@EnableAutoConfiguration
: Enables Spring Boot’s auto-configuration mechanism. -
@ComponentScan
: Scans for components in the current package and sub-packages. -
@Configuration
: Marks the class as a source of bean definitions.
-
The SpringApplication.run()
method is invoked to start the application and triggers the entire startup process.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. Startup Process
2.1 SpringApplication Initialization & Detection
- A
SpringApplication
object is created when the application is run. - Key tasks during initialization include:
- Detecting the application type (
SERVLET
,REACTIVE
, orNONE
). - Loading
ApplicationContextInitializers
andApplicationListeners
. - Setting default properties for the application.
- Detecting the application type (
The application type is set using the
SpringApplication
class. The detection logic is encapsulated in thededuceApplicationType()
method.
SERVLET: A traditional web application based on the Servlet API.
- Detected if
javax.servlet.Servlet
orjavax.servlet.http.HttpServletRequest
is on the classpath. -
spring-boot-starter-web
dependency.
REACTIVE: A reactive web application built using Spring WebFlux.
- Detected if
org.springframework.web.reactive.DispatcherHandler
or related WebFlux classes are present on the classpath. -
spring-boot-starter-webflux
dependency.
NONE: A non-web application, such as a batch or CLI tool.
- Selected if neither the SERVLET nor REACTIVE indicators are found.
- This is typical for applications that do not need a web server, such as CLI tools or batch processing jobs.
//CONSTRUCTOR
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//NOTE THIS
this.properties.setWebApplicationType(WebApplicationType.deduceFromClasspath());
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
//DEDUCE LOGIC
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;
}
What Happens After Detection
1. Setting the Application Context
Based on the detected type, Spring Boot selects the appropriate ApplicationContext implementation:
-
AnnotationConfigServletWebServerApplicationContext
for SERVLET. -
AnnotationConfigReactiveWebServerApplicationContext
for REACTIVE. -
AnnotationConfigApplicationContext
for NONE.
2. Configuring the Embedded Server
- For SERVLET applications, an embedded servlet container (e.g., Tomcat, Jetty) is initialized.
- For REACTIVE applications, a reactive server (e.g., Netty) is initialized.
- For NONE, no server is started.
3. Initializing Dispatcher
- SERVLET: The
DispatcherServlet
is configured for handling HTTP requests. - REACTIVE: The
DispatcherHandler
is initialized for reactive request handling.
2.2 Application Listeners Execution
-
ApplicationListeners
handle various lifecycle events during startup, such as environment preparation and context initialization. - Examples of lifecycle events include:
- Preparing the environment.
- Initializing the application context.
How to Listen to Events
1. Implementing ApplicationListener
Interface
@Component
gets initiated with with SpringApplication.run(DemoApplication.class, args);
@Slf4j
@Component
public class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
log.info("[LOG] ApplicationReadyEvent Listner via Component: Application is ready.");
}
}
whereas, if Stereotype annotation is not used, then add explicitly
@Slf4j
public class ApplicationStartingListener implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent event) {
log.info("[LOG] ApplicationStartingEvent: Application is starting...");
}
}
Explicit adding
public static void main(String[] args) {
SpringApplication app = new SpringApplication(DemoApplication.class);
// Add event listeners for logging application lifecycle
app.addListeners(new ApplicationStartingListener());
app.run(args);
}
2. Using @EventListener
Annotation
@Component
public class MyEventListener {
@EventListener
public void handleReadyEvent(ApplicationReadyEvent event) {
log.info("Application is ready!");
}
}
3. Programmatically Adding Listeners
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.addListeners(event -> {
if (event instanceof ApplicationReadyEvent) {
System.out.println("Application is ready!");
}
});
app.run(args);
}
Sequence of Events
-
ApplicationStartingEvent
- Triggered when the application starts.
- No context or environment is available.
-
ApplicationEnvironmentPreparedEvent
- Triggered when the environment is prepared (properties, profiles, etc.).
- Context is not created yet.
-
ApplicationContextInitializedEvent
- Triggered after the context is initialized but before bean definitions are loaded.
-
ApplicationPreparedEvent
- Triggered after the context is prepared but before it is refreshed.
-
ApplicationStartedEvent
- Triggered after the context is refreshed and before runners are invoked.
-
ApplicationReadyEvent
- Triggered after runners have been executed and the application is ready to serve requests.
-
ContextClosedEvent
- Triggered during shutdown when the context is closing.
-
ApplicationFailedEvent
- Triggered if the application fails to start due to an exception.
2.3 Banner
Either use app config
spring:
main:
banner-mode: "off"
Or use java code
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setBannerMode(Banner.Mode.OFF); // Example of customizing the startup
app.run(args);
}
3. Environment Preparation
Spring Boot creates and configures an Environment
object to manage application
properties and profiles.
Key steps include:
- Loading properties from various sources:
- Configuration files (e.g.,
application.properties
orapplication.yml
). - Environment variables.
- Command-line arguments.
- Configuration files (e.g.,
- Determining and activating profiles for different environments, such as
dev
orprod
.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.addListeners(event -> {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
System.out.println("Environment Prepared: " + event);
}
});
app.run(args);
}
}
4. Creating the Application Context
In Spring Boot, the creation of the ApplicationContext
is a critical step that
determines the environment and structure of the application.
What is the Application Context?
The ApplicationContext
is an interface in Spring that provides the
following functionalities:
- Loading and managing beans.
- Resolving dependencies.
- Publishing and listening to application events.
- Integrating with the environment.
Spring Boot dynamically selects the appropriate ApplicationContext
implementation based on the application type.
Types of Application Contexts in Spring Boot
Spring Boot uses different types of ApplicationContext
implementations
depending on the detected application type:
-
Servlet-Based Applications:
-
Context Used:
ServletWebServerApplicationContext
- Purpose: Configures a servlet-based web application with an embedded web server like Tomcat or Jetty.
- Usage: Typical for traditional web applications built with Spring MVC.
-
Context Used:
-
Reactive Applications:
-
Context Used:
ReactiveWebServerApplicationContext
- Purpose: Configures a reactive web application using WebFlux and an embedded reactive server like Netty.
- Usage: For modern, non-blocking, and event-driven applications.
-
Context Used:
-
CLI or Non-Web Applications:
-
Context Used:
GenericApplicationContext
- Purpose: Configures an application without a web server, such as batch jobs or command-line tools.
- Usage: For non-web Spring Boot applications
-
Context Used:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setApplicationContextClass(AnnotationConfigApplicationContext.class); // Setting custom ApplicationContext
ConfigurableApplicationContext context = app.run(args);
log.info("[LOG] ApplicationContext in use: {}", context.getClass().getName());
}
What Happens During Application Context Creation
Bean Definitions:
- The
ApplicationContext
scans for and registers bean definitions (via@ComponentScan
,@Configuration
, etc.).
Configuration Processing:
- Processes configuration classes (
@Configuration
) and applies Spring Boot’s auto-configuration.
Environment Integration:
- Integrates application properties and profiles into the context.
Lifecycle Event Publishing:
- Publishes lifecycle events such as
ApplicationStartedEvent
andContextRefreshedEvent
.
5. Auto-Configuration and Component Scanning
Spring Boot evaluates conditions defined in each auto-configuration class
(e.g., @ConditionalOnClass
, @ConditionalOnProperty
) to decide if the class should be applied.
5.1 Component Scanning
- The
@ComponentScan
annotation scans the base package and sub-packages for Spring-managed components, such as:- Services
- Repositories
- Controllers
- Configuration classes
@Component
public class MyService {
public void serve() {
System.out.println("Service is running");
}
}
5.2 Auto-Configuration
- Auto-configuration uses the
@EnableAutoConfiguration
annotation. - It leverages
META-INF/spring.factories
to load relevant configuration classes automatically. - Conditional annotations (
@Conditional
) determine which configurations should be applied.@Configuration @ConditionalOnMissingBean(MyService.class) public class MyServiceAutoConfiguration { @Bean public MyService myService() { return new MyService(); } }
6. Bean Definitions and Dependency Injection
6.1 Bean Creation
- Beans are registered in the application context through:
- Component scanning.
- Explicit definitions in configuration classes.
- Auto-configuration.
6.2 Dependency Injection
- Dependencies are resolved and injected into beans through mechanisms like:
- Constructor injection.
- Field injection.
- Setter injection.
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@Component
public class MyBeanConsumer {
private final MyBean myBean;
@Autowired
public MyBeanConsumer(MyBean myBean) {
this.myBean = myBean;
}
public void printMessage() {
log.info("Bean is injected: " + myBean);
}
}
7. Application Context Refresh
The application context is refreshed to perform tasks such as:
- Instantiating and configuring all beans.
- Resolving placeholders and configuration properties.
- Registering and initializing any lifecycle components or runners.
@Component public class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.println("Context Refreshed: " + event); } }
8. Embedded Server Initialization (For Web Applications)
8.1 Server Startup
- The embedded web server (e.g., Tomcat, Jetty, or Undertow) is started during this phase.
8.2 DispatcherServlet Initialization
- The
DispatcherServlet
is registered in the servlet context and initialized to handle HTTP requests.
@RestController
public class MyController {
@GetMapping("/")
public String home() {
return "Welcome to Spring Boot!";
}
}
9. Application Execution
9.1 Lifecycle Events
- Spring Boot triggers application lifecycle events, including:
-
ApplicationStartedEvent
– Signaling the application startup phase. -
ApplicationReadyEvent
– Signaling that the application is ready.
-
9.2 Custom Logic Execution
- Any custom initialization logic defined in
CommandLineRunner
orApplicationRunner
beans is executed.@Component public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("Executing custom logic at startup"); } }
10. Application Ready
The application is fully initialized and ready to handle its tasks:
- For web applications, the server is ready to process requests.
-
For CLI or batch applications, the main process begins execution.
Summary
The Spring Boot startup process consists of several well-defined steps:
- Initializing the
SpringApplication
. - Preparing the environment and loading properties.
- Creating and refreshing the application context.
- Registering beans and performing dependency injection.
- Starting the embedded server (if applicable).
- Running custom application logic.