Skip to content

Instantly share code, notes, and snippets.

@carefree-ladka
Created February 26, 2026 15:16
Show Gist options
  • Select an option

  • Save carefree-ladka/7d6e30b908334bc5b229f2f3dbebef68 to your computer and use it in GitHub Desktop.

Select an option

Save carefree-ladka/7d6e30b908334bc5b229f2f3dbebef68 to your computer and use it in GitHub Desktop.
Spring Boot Internals

Spring Boot Internals

A deep-dive into how Spring Boot reduces configuration and starts your app automatically. Great for interview prep and understanding the framework under the hood.


Table of Contents

  1. What Happens When You Run a Spring Boot App
  2. @SpringBootApplication Explained
  3. Auto-Configuration Internals
  4. Conditional Configuration
  5. Starter Dependencies
  6. Embedded Server Internals
  7. SpringApplication Internals
  8. Bean Lifecycle in Boot
  9. External Configuration Binding
  10. Actuator Internals
  11. How Boot Reduces Boilerplate
  12. Disabling Auto-Configuration
  13. Important Internal Classes
  14. Full Execution Flow
  15. Custom Auto-Configuration
  16. Spring Boot Profiles
  17. Property Source Priority Order
  18. Failsafe Interview Answer

1. What Happens When You Run a Spring Boot App

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

Behind the scenes, in order:

  1. SpringApplication.run() starts
  2. Creates ApplicationContext
  3. Performs auto-configuration
  4. Scans components
  5. Starts embedded server (Tomcat / Jetty / Undertow)
  6. Application is ready

2. @SpringBootApplication Explained

@SpringBootApplication is a meta-annotation that combines three annotations:

@SpringBootConfiguration   // Same as @Configuration — marks class as config source
@EnableAutoConfiguration   // Triggers Spring Boot magic (most important)
@ComponentScan             // Scans @Component, @Service, @Repository, @Controller, @RestController

What @ComponentScan picks up

Annotation Purpose
@Component Generic Spring-managed bean
@Service Business logic layer
@Repository Data access layer (also wraps persistence exceptions)
@Controller MVC controller
@RestController @Controller + @ResponseBody

3. Auto-Configuration Internals

This is the core of Spring Boot and where most interview questions originate.

How It Works

When @EnableAutoConfiguration runs, it triggers AutoConfigurationImportSelector, which reads:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Note: In Spring Boot 2.x this was META-INF/spring.factories. Boot 3.x migrated to the .imports file.

That file contains a list of configuration classes, for example:

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

Spring loads them conditionally — not all at once.


4. Conditional Configuration

Auto-config works because of @Conditional annotations. These are the "magic" conditions:

Annotation Meaning
@ConditionalOnClass Activate if class is on classpath
@ConditionalOnMissingBean Activate if bean is NOT already defined
@ConditionalOnProperty Activate if a property is set to a value
@ConditionalOnMissingClass Activate if class is NOT on classpath
@ConditionalOnBean Activate if a specific bean IS already defined
@ConditionalOnWebApplication Activate only in a web context

Example — DataSourceAutoConfiguration

@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
public class DataSourceAutoConfiguration {
    // Creates a default DataSource bean
}

Translation:

  • If DataSource class exists on the classpath AND
  • No DataSource bean is manually defined
  • THEN create a default DataSource bean

Boot says: "If you don't configure it, I'll configure it for you."

But if you define your own bean → Boot backs off automatically.


5. Starter Dependencies

Starters are curated dependency bundles. They put the right classes on the classpath so auto-configuration can trigger.

Example: spring-boot-starter-web

Pulls in:

  • spring-web
  • spring-webmvc
  • jackson (JSON serialization)
  • tomcat (embedded server)
  • validation

Because the required classes are now on the classpath → WebMvcAutoConfiguration, DispatcherServletAutoConfiguration, etc. all trigger.

Key insight: Classpath presence = Feature activation

Other Common Starters

Starter What it activates
spring-boot-starter-data-jpa Hibernate, JPA, DataSource
spring-boot-starter-security Spring Security filter chain
spring-boot-starter-test JUnit 5, Mockito, AssertJ
spring-boot-starter-actuator Health, metrics, info endpoints
spring-boot-starter-webflux Reactive Netty server

6. Embedded Server Internals

Spring Boot embeds the server using ServletWebServerApplicationContext.

Dependency Server
spring-boot-starter-web Tomcat (default)
spring-boot-starter-web + Jetty excluded Jetty
spring-boot-starter-webflux Netty (reactive)

Boot creates a TomcatServletWebServerFactory and starts Tomcat programmatically — no web.xml needed.

Swapping the server

<!-- Exclude Tomcat and add Jetty -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

7. SpringApplication Internals

SpringApplication.run() goes through five steps:

Step 1 — Create SpringApplication Instance

Detects the application type:

Detection Type
DispatcherServlet on classpath Servlet-based web app
DispatcherHandler on classpath Reactive web app
Neither Non-web / CLI app

Step 2 — Prepare Environment

Loads properties from (in order):

  • application.properties / application.yml
  • Active profiles (application-{profile}.properties)
  • Command-line args
  • System environment variables

Step 3 — Create ApplicationContext

App Type Context Class
Servlet AnnotationConfigServletWebServerApplicationContext
Reactive AnnotationConfigReactiveWebServerApplicationContext
Non-web AnnotationConfigApplicationContext

Step 4 — Apply Initializers & Listeners

  • ApplicationContextInitializer — runs before context refresh
  • ApplicationListener — reacts to application events (e.g., ApplicationReadyEvent)

Step 5 — Refresh Context

This is where everything happens:

  • Beans are created
  • Dependencies injected
  • Auto-configuration executed
  • Embedded server started

8. Bean Lifecycle in Boot

During context refresh, beans go through this lifecycle:

Bean definitions loaded
        ↓
BeanFactoryPostProcessor runs  ← modifies bean definitions (e.g., PropertySourcesPlaceholderConfigurer)
        ↓
BeanPostProcessor registered   ← will wrap/proxy beans later
        ↓
Beans instantiated (constructor called)
        ↓
Dependency injection (@Autowired, @Value)
        ↓
BeanPostProcessor#postProcessBeforeInitialization
        ↓
@PostConstruct / afterPropertiesSet()
        ↓
BeanPostProcessor#postProcessAfterInitialization  ← AOP proxies created here
        ↓
Bean is ready
        ↓
@PreDestroy / destroy()  ← on context shutdown

9. External Configuration Binding

Spring Boot binds external properties to beans using @ConfigurationProperties and the Binder API.

@ConfigurationProperties(prefix = "server")
public class ServerProperties {
    private int port;
    // getters and setters
}
server.port=8081

Relaxed Binding

Spring Boot supports multiple formats for the same property:

Format Example
Kebab-case (canonical) server.port
Camel-case server.Port
Underscore server_port
UPPERCASE env var SERVER_PORT

10. Actuator Internals

Adding spring-boot-starter-actuator triggers auto-configuration of production-ready endpoints:

Endpoint Path Description
health /actuator/health App health status
metrics /actuator/metrics Micrometer metrics
beans /actuator/beans All registered beans
env /actuator/env Environment properties
conditions /actuator/conditions Auto-config conditions report
mappings /actuator/mappings All @RequestMapping paths

All endpoints are conditionally loaded via @ConditionalOnAvailableEndpoint.


11. How Boot Reduces Boilerplate

Without Spring Boot With Spring Boot
XML configs (applicationContext.xml) Zero XML required
Manual DispatcherServlet registration Auto-configured
Manual DataSource creation Auto-configured from properties
Manual server setup (web.xml, WAR) Embedded server, runnable JAR
Manual transaction manager Auto-configured
Dozens of @Bean methods Sensible defaults via auto-config

12. Disabling Auto-Configuration

Option 1 — Annotation-level:

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class App { ... }

Option 2 — Properties:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

Option 3 — Exclude specific auto-config at test level:

@SpringBootTest
@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
class MyTest { ... }

13. Important Internal Classes

Class Role
SpringApplication Entry point, bootstraps the application
AutoConfigurationImportSelector Reads and imports auto-config classes
ConditionEvaluator Evaluates @Conditional annotations
SpringFactoriesLoader Loads classes from META-INF/spring.factories (Boot 2)
Binder Binds external properties to @ConfigurationProperties
ConfigurationClassPostProcessor Processes @Configuration classes
TomcatServletWebServerFactory Creates and starts the embedded Tomcat instance
BeanDefinitionLoader Loads bean definitions from sources
ConditionEvaluationReport Records which conditions passed/failed (visible via /actuator/conditions)

14. Full Execution Flow

main()
  ↓
SpringApplication.run()
  ↓
Detect application type (Servlet / Reactive / None)
  ↓
Load SpringApplicationRunListeners
  ↓
Prepare Environment (properties, profiles, args)
  ↓
Print Banner
  ↓
Create ApplicationContext
  ↓
Load AutoConfiguration classes (from .imports file)
  ↓
Apply @Conditional checks
  ↓
Register & create Beans
  ↓
BeanPostProcessor processing (AOP, validation, etc.)
  ↓
Start Embedded Server
  ↓
Publish ApplicationReadyEvent
  ↓
Application is ready 🚀

15. Custom Auto-Configuration

You can write your own auto-configuration — useful when building libraries or internal frameworks.

Steps

1. Create a configuration class:

@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnMissingBean(MyService.class)
public class MyServiceAutoConfiguration {

    @Bean
    public MyService myService() {
        return new MyService();
    }
}

2. Register it (Spring Boot 3.x):

Create src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:

com.example.MyServiceAutoConfiguration

For Spring Boot 2.x, register in META-INF/spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.MyServiceAutoConfiguration

16. Spring Boot Profiles

Profiles let you switch configuration between environments (dev, staging, prod).

# application.properties
spring.profiles.active=dev
# application-dev.properties
server.port=8080
spring.datasource.url=jdbc:h2:mem:devdb

# application-prod.properties
server.port=80
spring.datasource.url=jdbc:postgresql://prod-host/mydb

Profile-conditional beans

@Bean
@Profile("dev")
public DataSource devDataSource() { ... }

@Bean
@Profile("prod")
public DataSource prodDataSource() { ... }

17. Property Source Priority Order

Spring Boot resolves properties in this order (highest priority first):

  1. Command-line arguments (--server.port=9090)
  2. SPRING_APPLICATION_JSON (env variable / system property)
  3. @TestPropertySource (in tests)
  4. System environment variables (SERVER_PORT)
  5. application-{profile}.properties
  6. application.properties / application.yml
  7. @PropertySource annotations on @Configuration classes
  8. Default properties (SpringApplication.setDefaultProperties)

🎯 Failsafe Interview Answer

Q: "How does Spring Boot Auto-Configuration work?"

Spring Boot uses @EnableAutoConfiguration which triggers AutoConfigurationImportSelector. It reads configuration classes from META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. These classes are applied conditionally — based on classpath presence (@ConditionalOnClass), existing beans (@ConditionalOnMissingBean), and properties (@ConditionalOnProperty). If conditions match, Boot configures beans automatically. If the user defines a bean manually, Boot backs off. Starter dependencies work by pulling the right classes onto the classpath, which activates the corresponding auto-configurations.

Follow-up questions to expect:

  • How would you write your own auto-configuration?
  • What's the difference between @Component scanning and auto-configuration?
  • How do you debug which conditions passed or failed? → /actuator/conditions
  • What changed in Spring Boot 3.x? → AutoConfiguration.imports replaced spring.factories
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment