How Spring Boot Auto-Configuration Works
Automatic configuration is the heart of Spring Boot—it automatically registers beans based on the classes in the classpath, allowing you to follow the "convention over configuration" principle.
1. What You'll Learn
@EnableAutoConfigurationand the Automatic Configuration Loading Mechanism- Conditional annotations:
@ConditionalOnClass/@ConditionalOnMissingBean/@ConditionalOnProperty - Steps for Creating Custom Starters and Naming Conventions
- Use the
--debugmode to view the auto-configuration report @SpringBootApplication(exclude = {...})Exclude specific automatic configurations
2. A True Story from a Framework Developer
(1) Pain Point: Having to write a bunch of configuration settings every time you integrate
Alice's team needs to integrate a new payment SDK into OrderFlow. Every time they integrate a new component, they have to write a @Configuration class, declare beans, configure properties, and handle conditional loading. Bob, a member of the team, often works late into the night due to bean conflicts and circular dependencies; just configuring a single Redis integration took him three days.
(2) Solutions for Automatic Configuration
Spring Boot Starter simplifies "integrating a component" to "adding a dependency":
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Once you add this dependency, the Redis connection factory and RedisTemplate are both automatically configured.
(3) Revenue
After Alice created the OrderFlow custom starter, new team members can integrate the payment SDK by simply adding a single dependency—there's no longer any need to manually configure any beans, and integration time has been reduced from 3 days to 30 minutes.
3. Automatic Configuration Loading Mechanism
(1) From @EnableAutoConfiguration to AutoConfiguration.imports
flowchart LR
A["@EnableAutoConfiguration"] --> B["Import<br/>AutoConfigurationImportSelector"]
B --> C["Read<br/>META-INF/spring/<br/>AutoConfiguration.imports"]
C --> D["Filter via<br/>@Conditional<br/>Annotations"]
D --> E["Register<br/>Qualified<br/>Auto-Configuration Classes"]
| Version | Load File | Format |
|---|---|---|
| Spring Boot 2.x | META-INF/spring.factories |
key=class1,class2 |
| Spring Boot 3.x | META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |
One fully qualified class name per line |
AutoConfiguration.imports file and no longer uses spring.factories to register auto-configuration.
(2) The Nature of Auto-Configuration Classes
An auto-configuration class is a @Configuration class with conditional annotations:
(1) ▶ Example: Simplifying the source code for DataSource auto-configuration
@AutoConfiguration
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource dataSource(DataSourceProperties properties) {
return DataSourceBuilder.create()
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword())
.build();
}
}
Output:
// Execution successful
4. A Detailed Explanation of Conditional Annotations
(1) Core Condition Annotations
| Note | Conditions | Typical Applications |
|---|---|---|
@ConditionalOnClass |
The specified class exists in the classpath | It only takes effect after the dependency is included |
@ConditionalOnMissingClass |
Class not found in classpath | Provide an alternative when a dependency is missing |
@ConditionalOnBean |
A specified bean exists in the container | Used when depending on other beans |
@ConditionalOnMissingBean |
The specified bean does not exist in the container | Provide a default bean; yield to user-defined beans when available |
@ConditionalOnProperty |
Configuration properties meet the conditions | Control functions via configuration switches |
(1) ▶ Example: @ConditionalOnProperty Toggle Control
@Configuration
@ConditionalOnProperty(
prefix = "orderflow.notification",
name = "enabled",
havingValue = "true",
matchIfMissing = false
)
public class NotificationConfig {
@Bean
public NotificationService emailNotificationService() {
return new EmailNotificationService();
}
}
Output:
// Execution successful
orderflow:
notification:
enabled: true # Set false to disable notification
(2) ▶ Example: @ConditionalOnMissingBean provides a default implementation
@Configuration
public class OrderFlowAutoConfiguration {
@Bean
@ConditionalOnMissingBean(IdGenerator.class)
public IdGenerator uuidIdGenerator() {
return new UuidIdGenerator();
}
@Bean
@ConditionalOnMissingBean(OrderNumberGenerator.class)
@ConditionalOnProperty(
prefix = "orderflow.order",
name = "number-prefix",
havingValue = "ORD",
matchIfMissing = true
)
public OrderNumberGenerator defaultOrderNumberGenerator() {
return new SequentialOrderNumberGenerator("ORD");
}
}
Output:
// Execution successful
5. Custom Starter
(1) Starter Naming Conventions
| Type | Naming Convention | Example |
|---|---|---|
| Official Starter | spring-boot-starter-* |
spring-boot-starter-web |
| Third-Party Starter | *-spring-boot-starter |
orderflow-spring-boot-starter |
(2) Starter Project Structure
orderflow-spring-boot-starter/
├── src/main/
│ ├── java/com/orderflow/autoconfigure/
│ │ ├── OrderFlowAutoConfiguration.java
│ │ └── OrderFlowProperties.java
│ └── resources/
│ └── META-INF/spring/
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
└── pom.xml
(1) ▶ Example: Complete code for a custom Starter
// OrderFlowProperties.java
@ConfigurationProperties(prefix = "orderflow.notification")
public record OrderFlowNotificationProperties(
boolean enabled,
String fromEmail,
String templatePath
) {}
// OrderFlowAutoConfiguration.java
@AutoConfiguration
@ConditionalOnClass(JavaMailSender.class)
@ConditionalOnProperty(
prefix = "orderflow.notification",
name = "enabled",
havingValue = "true"
)
@EnableConfigurationProperties(OrderFlowNotificationProperties.class)
public class OrderFlowAutoConfiguration {
@Bean
@ConditionalOnMissingBean(NotificationService.class)
public NotificationService notificationService(
OrderFlowNotificationProperties props) {
return new EmailNotificationService(
props.fromEmail(),
props.templatePath()
);
}
}
Output:
Execution successful
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.orderflow.autoconfigure.OrderFlowAutoConfiguration
6. Debugging and Troubleshooting Automatic Configuration
(1) --debug mode
When you add the --debug parameter at startup, Spring Boot outputs an auto-configuration report:
java -jar orderflow-service.jar --debug
(1) ▶ Example: Interpreting the Automatic Configuration Report
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required class 'javax.sql.DataSource'
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory'
Exclusions:
-----------
None
Unconditional classes:
----------------------
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
Output:
Execution successful
| Report Area | Meaning |
|---|---|
| Positive matches | Automatic configurations that meet the criteria and are active |
| Negative matches | Automatic configurations that do not meet the criteria and are not in effect |
| Exclusions | Explicitly Excluded Auto-Configurations |
| Unconditional Classes | Automatic Configuration for Unconditional Registration |
(2) Exclude automatic configuration
(2) ▶ Example: Excluding Unwanted Automatic Configurations
// Method 1: Annotation exclusion
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class OrderFlowApplication { ... }
// Method 2: Configuration property
// application.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Output:
// Execution successful
| Exclusion Method | Applicable Scenarios | Flexibility |
|---|---|---|
@SpringBootApplication(exclude) |
Always Exclude | Determined at Compile Time |
spring.autoconfigure.exclude |
Exclude by environment | Runtime-variable |
@ConditionalOnProperty |
Exclude by criteria | Most flexible |
7. Comprehensive Example: Complete Implementation of the OrderFlow Notification Starter
// orderflow-notification-spring-boot-starter
// OrderFlowNotificationProperties.java
package com.orderflow.autoconfigure;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "orderflow.notification")
public record OrderFlowNotificationProperties(
boolean enabled,
String fromEmail,
String templatePath,
SmtpConfig smtp
) {
public record SmtpConfig(String host, int port, boolean ssl) {}
}
// NotificationService.java
package com.orderflow.autoconfigure;
public interface NotificationService {
void send(String to, String subject, String body);
}
// EmailNotificationService.java
package com.orderflow.autoconfigure;
public class EmailNotificationService implements NotificationService {
private final String fromEmail;
private final String templatePath;
public EmailNotificationService(String fromEmail, String templatePath) {
this.fromEmail = fromEmail;
this.templatePath = templatePath;
}
@Override
public void send(String to, String subject, String body) {
// Email sending logic
System.out.printf("Send to %s: [%s] %s%n", to, subject, body);
}
}
// OrderFlowNotificationAutoConfiguration.java
package com.orderflow.autoconfigure;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass(name = "org.springframework.mail.javamail.JavaMailSender")
@ConditionalOnProperty(prefix = "orderflow.notification", name = "enabled", havingValue = "true")
@EnableConfigurationProperties(OrderFlowNotificationProperties.class)
public class OrderFlowNotificationAutoConfiguration {
@Bean
@ConditionalOnMissingBean(NotificationService.class)
public NotificationService notificationService(OrderFlowNotificationProperties props) {
return new EmailNotificationService(props.fromEmail(), props.templatePath());
}
}
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.orderflow.autoconfigure.OrderFlowNotificationAutoConfiguration
❓ FAQ
📖 Summary
- Using the
AutoConfiguration.importsfile to register auto-configuration classes in Spring Boot 3.x - The core of the auto-configuration class is the conditional annotations:
@ConditionalOnClass,@ConditionalOnMissingBean,@ConditionalOnProperty @ConditionalOnMissingBeanImplementing the "User-Defined Priority" Principle- Custom Starter Names: Official
spring-boot-starter-*, Third-party*-spring-boot-starter - You can view the auto-configuration report in
--debugmode and via the Actuator endpoint
📝 Exercises
-
Basic Exercise (Difficulty ⭐): Start the OrderFlow project using the
--debugmode, list all auto-configuration classes among the "Positive matches," and understand the classpath conditions required for each auto-configuration. -
Advanced Exercise (Difficulty: ⭐⭐): Create a
orderflow-spring-boot-starterthat includes a notification feature controlled by the@ConditionalOnPropertyswitch, then integrate it into the OrderFlow project and test it. -
Challenge (Difficulty: ⭐⭐⭐): Implement an auto-configuration system that supports multiple implementations—use Kafka notifications if Kafka is present in the classpath, email notifications otherwise, and log notifications if neither is available. Consider the priority and mutual exclusion design of conditional annotations.



