Auto-Configuration
Definition
Auto-configuration is Boot creating beans for you automatically when certain conditions are met, such as a library being on the classpath. If you define your own bean, the automatic one steps aside.
Why it exists
Setting up a data source, JSON mapper and web server is the same boilerplate in every project. Auto-configuration does the common setup and still lets you override any part.
How it works
The mechanism
@EnableAutoConfiguration(inside@SpringBootApplication) imports anAutoConfigurationImportSelector.- The selector reads the file
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsfrom every JAR on the classpath. Each line is a configuration class name. (Older Boot versions usedspring.factoriesfor this.) - Each candidate class is evaluated. Its
@Conditional...annotations decide whether it contributes beans. - Auto-configuration is processed after your own configuration, which is why your beans win.
Common conditions
| Annotation | Applies when |
|---|---|
@ConditionalOnClass / @ConditionalOnMissingClass | A class is (not) on the classpath |
@ConditionalOnBean / @ConditionalOnMissingBean | A bean of that type is (not) already defined |
@ConditionalOnProperty | A property has a given value |
@ConditionalOnWebApplication | Servlet or reactive web app |
@ConditionalOnResource | A file exists |
Example code
Overriding and excluding
Define your own bean and the default backs off:
@Configuration
class JsonConfig {
@Bean
ObjectMapper objectMapper() {
// JacksonAutoConfiguration's mapper is @ConditionalOnMissingBean, so this wins.
return new ObjectMapper().findAndRegisterModules();
}
}
Be careful: replacing the mapper this way drops Boot's defaults (for example spring.jackson.* properties). Often a Jackson2ObjectMapperBuilderCustomizer bean is the better tool.
To turn a configuration off entirely:
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class App { }
or spring.autoconfigure.exclude=... in properties.
Writing your own auto-configuration
This is how starters for your company's shared libraries work. A tiny example: a GreetingService that is created unless the application provides one, and can be switched off by property.
public class GreetingService {
private final String greeting;
public GreetingService(String greeting) {
this.greeting = greeting;
}
public String greet(String name) {
return greeting + ", " + name + "!";
}
}
@ConfigurationProperties(prefix = "greeting")
public class GreetingProperties {
private String message = "Hello";
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
}
@AutoConfiguration
@EnableConfigurationProperties(GreetingProperties.class)
@ConditionalOnProperty(prefix = "greeting", name = "enabled", matchIfMissing = true)
public class GreetingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
GreetingService greetingService(GreetingProperties props) {
return new GreetingService(props.getMessage());
}
}
Register it in src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
com.example.greeting.GreetingAutoConfiguration
Note that auto-configuration classes must not be found by component scanning of the consuming app; that is why they are listed in the imports file instead of being annotated with @Component.
System design considerations
- Run the application with the conditions report when upgrading Boot or dependencies
- Test custom auto-configuration with ApplicationContextRunner
- Namespace your properties and document defaults
Seeing what Boot decided
Start the app with --debug (or debug=true). The conditions evaluation report lists:
- Positive matches: configurations that were applied and why.
- Negative matches: configurations skipped and which condition failed.
- Exclusions and Unconditional classes.
The Actuator conditions endpoint exposes the same data on a running app.
When to use it, and when not
Use it when
- You want sensible defaults and override only what differs
- You build a shared starter for several teams
- You diagnose why a bean exists or does not
Think twice when
- You depend on a specific bean being configured but never verified the condition
- You exclude auto-configurations broadly without understanding what they provide
- Behaviour changes silently after a dependency upgrade
Common mistakes
- Using
@ConditionalOnBeanin application configuration, where bean registration order is unpredictable. - Overriding a bean by name or type and unintentionally losing property-driven customisation.
- Component-scanning an auto-configuration package, which bypasses the conditions.
- Forgetting the imports file after renaming a class; the configuration silently stops applying.
Interview questions
1. How does Spring Boot auto-configuration work?
@EnableAutoConfiguration loads candidate configuration class names from AutoConfiguration.imports files on the classpath. Each class is guarded by conditions; those that pass register beans. Since they are processed after user configuration and mostly use @ConditionalOnMissingBean, user-defined beans take precedence.
2. How do you find out why a bean was or was not created?
Run with --debug or call the Actuator /actuator/conditions endpoint. Negative matches show the failed condition.
3. How would you disable one auto-configuration?
exclude on @SpringBootApplication / @EnableAutoConfiguration, or the spring.autoconfigure.exclude property.
4. How do you create a custom starter?
Two modules by convention: an -autoconfigure module holding the @AutoConfiguration class, properties and the imports file, and a thin -starter module that depends on it plus the needed libraries. Name it acme-spring-boot-starter, not spring-boot-starter-acme (that prefix is reserved for the Boot team).
5. What is the difference between @ConditionalOnBean and @ConditionalOnMissingBean in terms of ordering?
Both depend on what has been registered so far, so they are only reliable in auto-configuration classes ordered with @AutoConfiguration(after = ...). In ordinary user configuration, ordering is not guaranteed and these conditions can behave unexpectedly.
Check yourself
1How does Boot decide to create a DataSource automatically?
2Which flag shows which auto-configurations matched or not?
3You define your own DataSource bean. What happens to the auto-configured one?
Key takeaways
- Auto-configuration = conditional
@Configurationclasses listed inAutoConfiguration.imports. - It runs after user configuration and backs off via
@ConditionalOnMissingBean. - Debug with
--debugor/actuator/conditions. - Custom starters are an autoconfigure module plus a thin starter module.
Next: Starters and dependency management.
Next topicConfiguration and propertiesFinished this page? Track your progress (saved only in your browser).