How auto-configuration works

Spring Boot · Advanced · 16 min

Knowing how Boot decides what to configure lets you override defaults confidently and debug startup.

Auto-configuration is ordinary Spring configuration that Boot applies conditionally. Each auto-configuration class is listed in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports inside the Boot jars (and in third-party starters). At startup Boot loads the list and evaluates each class's conditions:

  • @ConditionalOnClass(DataSource.class): only if a class is on the classpath. This is why adding a starter "turns on" a feature.
  • @ConditionalOnMissingBean: only if you haven't defined your own bean of that type. This is the back-off rule that lets your configuration win.
  • @ConditionalOnProperty(prefix = "app.cache", name = "enabled", havingValue = "true"): driven by configuration.
  • @ConditionalOnWebApplication, @ConditionalOnBean, @ConditionalOnResource and more.

Auto-configurations are processed after your own configuration, so the conditions see your beans. Ordering between them uses @AutoConfiguration(after = ...).

To customise, you rarely replace beans; first look for properties (spring.jackson.*) or customizer beans (Jackson2ObjectMapperBuilderCustomizer, WebServerFactoryCustomizer). Defining your own ObjectMapper or DataSource bean makes Boot's back off entirely. Exclude an auto-configuration with @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) or spring.autoconfigure.exclude.

Debug with --debug (or debug=true): the conditions evaluation report lists positive and negative matches with reasons. The /actuator/conditions endpoint shows the same at runtime.

Example

// A simplified version of what Boot ships, showing the patterns
@AutoConfiguration
@ConditionalOnClass(ObjectMapper.class)
public class SimpleJacksonAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean                    // backs off if you define one
    ObjectMapper objectMapper(ObjectProvider<MapperCustomizer> customizers) {
        ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
        customizers.orderedStream().forEach(c -> c.customize(mapper));
        return mapper;
    }
}
interface MapperCustomizer { void customize(ObjectMapper mapper); }
// Your app: tweak instead of replace
@Bean
MapperCustomizer indent() {
    return m -> m.enable(SerializationFeature.INDENT_OUTPUT);
}
// java -jar app.jar --debug
// Positive matches:  SimpleJacksonAutoConfiguration matched: @ConditionalOnClass found ObjectMapper
// Negative matches:  DataSourceAutoConfiguration: did not find required class
//                    'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'

Remember

  • Auto-configurations are conditional @Configuration classes listed in AutoConfiguration.imports
  • @ConditionalOnClass reacts to the classpath; @ConditionalOnMissingBean lets your beans win
  • Prefer properties and customizer beans over replacing auto-configured beans
  • --debug prints the conditions evaluation report

Watch out for

  • Defining your own ObjectMapper bean to change one setting and losing all of Boot's Jackson configuration.

Check yourself

  1. You define your own DataSource bean. What does DataSourceAutoConfiguration do?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.spring.io/spring-boot/reference/features/developing-auto-configuration.html