Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Spring Boot REST API Development

Spring Boot Basics

  • What is Spring Boot?
  • Dependency Injection
  • Building REST Controllers

Validation & Error Handling

  • Bean Validation with @Valid
  • Global Exception Handling

Spring Framework Internals

  • IoC Container Fundamentals
  • Bean Lifecycle In Detail
  • Component Scanning & Configuration
  • Auto-Configuration Mechanism
  • Spring AOP
  • @Transactional Deep Dive

Microservices Architecture

  • Monolith to Microservices Decomposition
  • API Gateway
  • Service Discovery
  • Inter-Service Communication Choices
  • Event-Driven Architecture Patterns
  • Messaging Technology Choices

Resilience Patterns

  • Configuration Management
  • Circuit Breaker Pattern
  • Retry & Backoff Strategies
  • Bulkhead & Rate Limiting
  • Timeout Strategy
  • Why Microservices Fail

Distributed Data & Consistency Patterns

  • Two-Phase Commit
  • Saga Pattern
  • Outbox Pattern
  • Eventual Consistency Design
  • CQRS Basics
  • CAP Theorem

Observability & Operations

  • Centralized Logging
  • Distributed Tracing
  • Metrics & Monitoring
  • Alerting Strategy
  • Health Checks

Payment Systems

  • Payment — Requirements
  • Payment — Core Flow
  • Payment — Idempotency Implementation
  • Payment — Failure Handling & Reconciliation
  • Payment — Security

Order Management System

  • OMS — Requirements
  • OMS — State Machine Design
Chaturmind
← Spring Boot REST API Development

Spring Boot Basics

  • What is Spring Boot?
  • Dependency Injection
  • Building REST Controllers

Validation & Error Handling

  • Bean Validation with @Valid
  • Global Exception Handling

Spring Framework Internals

  • IoC Container Fundamentals
  • Bean Lifecycle In Detail
  • Component Scanning & Configuration
  • Auto-Configuration Mechanism
  • Spring AOP
  • @Transactional Deep Dive

Microservices Architecture

  • Monolith to Microservices Decomposition
  • API Gateway
  • Service Discovery
  • Inter-Service Communication Choices
  • Event-Driven Architecture Patterns
  • Messaging Technology Choices

Resilience Patterns

  • Configuration Management
  • Circuit Breaker Pattern
  • Retry & Backoff Strategies
  • Bulkhead & Rate Limiting
  • Timeout Strategy
  • Why Microservices Fail

Distributed Data & Consistency Patterns

  • Two-Phase Commit
  • Saga Pattern
  • Outbox Pattern
  • Eventual Consistency Design
  • CQRS Basics
  • CAP Theorem

Observability & Operations

  • Centralized Logging
  • Distributed Tracing
  • Metrics & Monitoring
  • Alerting Strategy
  • Health Checks

Payment Systems

  • Payment — Requirements
  • Payment — Core Flow
  • Payment — Idempotency Implementation
  • Payment — Failure Handling & Reconciliation
  • Payment — Security

Order Management System

  • OMS — Requirements
  • OMS — State Machine Design
HomeLearnSpring BootSpring Boot REST API DevelopmentSpring Framework Internals
✓ FreeAdvanced· 14 min read

Auto-Configuration Mechanism

How Spring Boot actually decides what to configure automatically: the @Conditional family, writing a custom starter, and the five pillars — auto-config, starters, embedded server, externalized config, and Actuator.

Published September 23, 2026


Auto-Configuration Mechanism

What is Spring Boot? introduced auto-configuration at a high level — "add a starter, get beans for free." This lesson covers the actual mechanism making that happen.

AutoConfiguration.imports vs spring.factories

Spring Boot 3+ discovers auto-configuration classes via a file at META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports — a plain list of fully-qualified class names to consider. Before Spring Boot 3.0, the same role was played by an entry under org.springframework.boot.autoconfigure.EnableAutoConfiguration in META-INF/spring.factories, a more general-purpose (and more cluttered) mechanism shared with other Spring SPI hooks. The 3.0 change split auto-configuration discovery into its own dedicated file, purely for clarity and faster startup scanning — functionally, both mechanisms answer the same question: "which auto-configuration classes exist to consider."

The @Conditional family: deciding whether to actually apply

Being discovered doesn't mean a configuration class's beans get created — each auto-configuration class is typically covered in @Conditional* annotations that gate whether it actually activates:

@Configuration
@ConditionalOnClass(MongoClient.class)         // only activate if the Mongo driver is on the classpath
@ConditionalOnMissingBean(MongoTemplate.class) // back off if the developer already defined their own
class MongoAutoConfiguration {
    @Bean
    @ConditionalOnProperty(name = "app.mongo.enabled", havingValue = "true", matchIfMissing = true)
    MongoTemplate mongoTemplate(MongoClient client) { return new MongoTemplate(client); }
}
  • @ConditionalOnClass — only activate if a specific dependency is present on the classpath. This is why adding spring-boot-starter-data-mongodb "magically" configures a MongoTemplate: the condition checks for MongoClient.class, which that starter transitively pulls in.
  • @ConditionalOnMissingBean — back off entirely if the developer already defined their own bean of that type. This is the specific mechanism that makes auto-configuration overridable rather than a fixed, unchangeable default — define your own MongoTemplate bean, and Boot's auto-configured one simply never activates.
  • @ConditionalOnProperty — feature-flag-style activation, gated on an application.yml property value.
  • @ConditionalOnWebApplication / @ConditionalOnNotWebApplication — activate only in a web (servlet-based) context, or only in a non-web context, respectively — this is how the same Spring Boot dependency graph can auto-configure an embedded Tomcat only when it's actually relevant.

Writing a custom Spring Boot starter

A starter is really two artifacts: an autoconfigure module (the @Configuration class with its @Conditional beans, exactly the shape above) plus @ConfigurationProperties for type-safe, externally-configurable settings:

@ConfigurationProperties(prefix = "myservice")
class MyServiceProperties {
    private String apiKey;
    private int timeoutSeconds = 30; // sensible default
    // getters/setters
}

@Configuration
@EnableConfigurationProperties(MyServiceProperties.class)
@ConditionalOnClass(MyServiceClient.class)
class MyServiceAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    MyServiceClient myServiceClient(MyServiceProperties props) {
        return new MyServiceClient(props.getApiKey(), props.getTimeoutSeconds());
    }
}

A consuming application just adds the starter as a dependency and sets myservice.api-key in application.yml — no @Bean method of their own required, unless they want to override it.

Startup-time beans: CommandLineRunner / ApplicationRunner

@Component
class DataSeeder implements CommandLineRunner {
    public void run(String... args) { seedInitialData(); } // runs once, after the context is FULLY loaded
}

Beans implementing either interface have their run() method executed exactly once, automatically, right after the application context finishes loading — the standard place for startup data seeding or startup-time validation, without needing to hook into the bean lifecycle manually.

Fat JAR vs normal JAR

A normal JAR contains only your own compiled classes — running it requires separately placing every dependency JAR on the classpath. A fat (executable) JAR bundles all dependencies plus an embedded server inside one self-contained archive, which is exactly what spring-boot-maven-plugin/spring-boot-gradle-plugin produce by default — java -jar myapp.jar just works, with zero external classpath setup, because everything needed is already inside that one file.

Default logging, server port precedence, and Convention over Configuration

Spring Boot auto-configures Logback as the default logging implementation via spring-boot-starter-logging, with sensible console output requiring zero setup. Server port resolves via a defined precedence: command-line argument (--server.port=9090) > environment variable (SERVER_PORT) > application.yml/properties > default 8080 — this ordering follows Spring's general externalized-configuration precedence (more specific/runtime sources override more general/build-time ones), and it's exactly what Convention over Configuration means as Spring Boot's core design philosophy: sensible defaults apply automatically, and you only specify what genuinely differs from the convention — you never have to declare the default port, the default logging framework, or the default server, only override them when needed.

Embedded Tomcat auto-detection

Spring Boot inspects the classpath for a web starter dependency — finding spring-boot-starter-web (which transitively includes spring-boot-starter-tomcat), it auto-configures an embedded servlet container without any explicit @Bean for a server. This is the same @ConditionalOnClass mechanism as the Mongo example above, just applied to the embedded-server decision specifically.

@RestController vs @Controller

@RestController is exactly @Controller + @ResponseBody applied automatically to every method — meaning return values are serialized directly into the HTTP response body (typically as JSON, via Jackson), rather than being resolved as a view name for server-side template rendering. Nearly every Spring Boot API (as opposed to a server-rendered web app) uses @RestController for this reason.

Practical exception handling: @ControllerAdvice + @ExceptionHandler

@ControllerAdvice
class GlobalExceptionHandler {
    @ExceptionHandler(ResourceNotFoundException.class)
    ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(404).body(new ErrorResponse(ex.getMessage()));
    }
}

Centralizing exception-to-HTTP-response translation in one @ControllerAdvice class means individual controllers stay free of repetitive try/catch blocks — every controller in the application benefits from the same consistent error-response shape, defined once.

The five pillars

What distinguishes Spring Boot from plain Spring, stated as a checklist: auto-configuration (this lesson), embedded server (no WAR deployment), starter dependencies (curated bundles), externalized configuration (the precedence chain above), and Actuator (production-ready monitoring endpoints, out of scope for this lesson but worth naming as the fifth pillar).

Follow-up questions this topic invites — and their answers

Q: What happens if two different starters' auto-configuration classes both try to configure a bean of the same type? A: @ConditionalOnMissingBean is exactly the mechanism preventing conflict here too — Spring Boot's auto-configuration classes are ordered (via @AutoConfigureOrder/@AutoConfigureBefore/@AutoConfigureAfter), and whichever runs first successfully creates the bean; later auto-configurations checking @ConditionalOnMissingBean for the same type simply back off, avoiding a duplicate-bean conflict.

Q: Why does @ConditionalOnClass check the classpath instead of checking application.yml directly? A: Classpath presence and explicit configuration answer different questions — @ConditionalOnClass answers "could this feature even work, given what's installed," while @ConditionalOnProperty answers "has the developer explicitly asked for this behavior." Using classpath presence lets a dependency's mere inclusion trigger sensible auto-configuration without also requiring redundant explicit opt-in configuration for every single feature.

Q: Is @ConfigurationProperties an alternative to @Value, or do they serve different needs? A: @ConfigurationProperties binds an entire group of related properties into one typed object in one place (as shown above), while @Value injects a single property value at a single injection point — @ConfigurationProperties scales much better for a starter or module with many related settings, since it centralizes them into one validated, typed class rather than scattering individual @Value annotations across many classes.

Q: Could a poorly-written custom starter break auto-configuration for an unrelated part of the application? A: Yes — if a custom starter's @Conditional checks are too broad or its bean definitions collide with another module's beans without proper @ConditionalOnMissingBean guards, it can either fail to back off when it should or inadvertently prevent a legitimate bean elsewhere from being created, which is why careful, narrow conditions are considered a best practice when writing a starter meant for reuse across multiple applications.

Previous

Component Scanning & Configuration

Next

Spring AOP

AI Tutor

Lesson: Auto-Configuration Mechanism

Quick actions

AI responses can be inaccurate. Verify critical information.