Spring Boot Essentials

Auto-Configuration

18 min Lesson 4 of 13

Auto-Configuration

One of the most celebrated — and occasionally misunderstood — features of Spring Boot is auto-configuration: the ability to look at what is on your classpath, what beans you have already defined, and what properties you have set, then automatically wire together the infrastructure your application needs. This lesson unpacks exactly how that mechanism works under the hood, why it is designed the way it is, and how to control or override it when the defaults are not what you need.

The @SpringBootApplication Annotation

Every Spring Boot application starts with a class annotated with @SpringBootApplication. This single annotation is a composed shortcut for three separate annotations:

  • @SpringBootConfiguration — marks the class as a source of @Bean definitions (it is itself a specialisation of @Configuration).
  • @EnableAutoConfiguration — switches on the auto-configuration machinery described in this lesson.
  • @ComponentScan — tells Spring to scan the package of the annotated class (and its sub-packages) for @Component, @Service, @Repository, and @Controller classes.
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication // = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
Package placement matters. Because @ComponentScan scans the package of the annotated class and all sub-packages, the main class should live in a top-level package (e.g. com.example.demo), not in the default unnamed package or a deeply nested one. Every other class in the project should be in a sub-package of this root.

How Auto-Configuration Works Internally

When @EnableAutoConfiguration is present, Spring Boot loads a list of candidate auto-configuration classes. In Spring Boot 3, this list is read from META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports files on the classpath (in Spring Boot 2 it was spring.factories — the mechanism changed but the idea is the same). Each of the 150+ built-in auto-configuration classes is a regular @Configuration class guarded by conditional annotations.

The key conditional annotations are:

  • @ConditionalOnClass — the configuration applies only if a specific class is present on the classpath.
  • @ConditionalOnMissingBean — the auto-configured bean is created only if the application context does not already contain a bean of that type.
  • @ConditionalOnProperty — the configuration is activated only if a specific property is set (or has a certain value).
  • @ConditionalOnWebApplication — activates only in a servlet or reactive web context.
  • @ConditionalOnMissingClass — the inverse of @ConditionalOnClass.

For example, Spring Boot's DataSourceAutoConfiguration only fires if HikariCP (or another pool) is on the classpath AND no DataSource bean has been defined by you. Here is a simplified version showing the pattern:

@AutoConfiguration @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory") @EnableConfigurationProperties(DataSourceProperties.class) public class DataSourceAutoConfiguration { @Bean @ConditionalOnMissingBean public DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); } }
The "missing bean" pattern is the key to customisation. If you declare your own @Bean of the same type, the @ConditionalOnMissingBean guard causes Spring Boot to step back and use yours instead. You never fight the framework — you simply provide your own definition and auto-configuration yields.

The @AutoConfiguration Annotation

In Spring Boot 3, auto-configuration classes are annotated with @AutoConfiguration (rather than plain @Configuration). This signals to the framework that the class participates in the auto-configuration loading pipeline and should be processed after the application's own @Configuration classes — guaranteeing that user-defined beans win over auto-configured defaults.

Inspecting What Was Auto-Configured (and What Was Not)

You can ask Spring Boot to print a conditions report at startup. Set the following property:

# application.properties logging.level.org.springframework.boot.autoconfigure=DEBUG

This triggers the conditions report in the console. Every auto-configuration class is listed, and for each one you see either why it was applied (positive match) or why it was skipped (negative match). This is the first thing to read whenever auto-configuration is not behaving as you expect.

Alternatively, add spring-boot-starter-actuator and hit the /actuator/conditions endpoint in JSON for a structured view of the same data at runtime.

Excluding an Auto-Configuration Class

Sometimes you want to prevent a specific auto-configuration from running — for example, to disable the automatic DataSource setup in a service that does not need a database:

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

You can also exclude by class name (useful when the class is not on your compile-time classpath):

# application.properties spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

Writing Your Own Auto-Configuration

Auto-configuration is not restricted to the Spring Boot team. Any library can ship its own auto-configuration classes and register them in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. This is exactly how third-party starters (e.g. for Redis, Kafka, or Flyway) integrate transparently into any Spring Boot project. The pattern is always the same: conditions guard the beans, @ConditionalOnMissingBean defers to user customisation, and configuration properties bind via @ConfigurationProperties.

Do not rely on auto-configuration order for application beans. While Spring Boot ensures its own auto-configuration classes run after user @Configuration classes, you should never couple your own auto-configuration classes to each other via implicit ordering. Use @AutoConfigureAfter or @AutoConfigureBefore explicitly if ordering between auto-configurations matters.

Why Auto-Configuration Matters for Productivity

Before Spring Boot, wiring a web application meant writing dozens of lines of XML or Java configuration: DispatcherServlet registration, DataSource setup, Jackson ObjectMapper configuration, transaction manager declaration, and more. Auto-configuration encodes the community's best-practice defaults for each piece of infrastructure. You add a starter, and a sensible, production-ready configuration appears — one you can override precisely where you need to, without touching everything else.

Summary

@SpringBootApplication composes three annotations; the critical one for this lesson is @EnableAutoConfiguration. It triggers classpath scanning of candidate auto-configuration classes, each guarded by conditional annotations — most importantly @ConditionalOnClass and @ConditionalOnMissingBean. Declaring your own bean of a given type is all it takes to override an auto-configured default. When something does not work as expected, enable the conditions report with logging.level.org.springframework.boot.autoconfigure=DEBUG and read the positive and negative matches. In the next lesson you will see how the embedded server is itself wired up through exactly this mechanism.