Why this matters
- Understanding auto-config explains why adding a starter suddenly gives you a DataSource, Jackson, or SecurityFilterChain without writing config.
- Debugging "bean not found" or "bean already defined" conflicts requires knowing which auto-config class created the bean.
- Writing custom starters for shared BookStore libraries depends on the same conditional mechanism.
How auto-config loads
Boot 3.x reads candidate classes from:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
Each line is a fully qualified @Configuration class. AutoConfigurationImportSelector loads them after your own @Configuration classes, so your beans take precedence.
Example entry for the web starter:
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
Conditional evaluation
Every auto-config class uses @Conditional annotations:
@AutoConfiguration
@ConditionalOnClass(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.url")
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties props) {
return DataSourceBuilder.create()
.url(props.getUrl())
.username(props.getUsername())
.password(props.getPassword())
.build();
}
}
Beans register only when:
DataSource auto-config conditions
DataSourceclass is on the classpath (JPA starter present)spring.datasource.urlproperty is set- No user-defined
DataSource@Beanalready exists
Common @ConditionalOn* annotations
@ConditionalOnClass— Classpath contains the named class.@ConditionalOnMissingBean— No bean of this type registered yet (user override wins).@ConditionalOnProperty— Property matches expected value.@ConditionalOnWebApplication— Running as a servlet web app.@ConditionalOnExpression— SpEL expression evaluates to true.
User overrides auto-config
Your @Bean replaces auto-configured beans because of @ConditionalOnMissingBean:
@Configuration
public class TestDataSourceConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
Boot's DataSourceAutoConfiguration sees an existing DataSource and backs off.
Inspecting what matched
Enable the auto-config report:
debug: true
# or
logging:
level:
org.springframework.boot.autoconfigure: DEBUG
Startup logs list positive and negative matches:
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required class 'javax.sql.DataSource'
- @ConditionalOnProperty (spring.datasource.url) matched
RedisAutoConfiguration did not match:
- @ConditionalOnClass did not find required class 'org.springframework.data.redis.core.RedisOperations'
Auto-config ordering
@AutoConfigureBefore and @AutoConfigureAfter control relative order:
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
public class JpaRepositoriesAutoConfiguration { ... }
JPA repositories need a DataSource first — ordering prevents startup race conditions.
Disabling auto-config
Globally:
@SpringBootApplication(exclude = {
SecurityAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class
})
Via properties:
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
Use sparingly — excluding security in production BookStore is dangerous.
The @AutoConfiguration annotation
Boot 3 replaced @Configuration on auto-config classes with @AutoConfiguration for clearer semantics and ordering support. Custom starters should use:
@AutoConfiguration
@ConditionalOnClass(BookStoreClient.class)
public class BookStoreClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public BookStoreClient bookStoreClient(BookStoreProperties props) {
return new BookStoreClient(props);
}
}
Register in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
Quick recall
Everything you need if you only revisit this box.
- Auto-config classes load from
META-INF/spring/...AutoConfiguration.imports. - Each class uses
@ConditionalOn*to register beans only when appropriate. @ConditionalOnMissingBeanlets your@Beandefinitions override defaults.debug: trueprints positive and negative auto-config matches at startup.@AutoConfigureAfterensures beans likeDataSourceexist before JPA repos.- Custom starters use
@AutoConfiguration+ conditions + the imports file.
Test yourself
Answer these before moving on — recall is what makes it stick.