Why an auto-configuration did not fire

Spring Boot · lesson 29 of 39 · 5 min read

Read the condition evaluation report instead of guessing which annotation is missing.

Open this lesson in the learning hub

Key points

  • Every auto-configuration class carries conditions. When one does not apply, Spring records why - it does not discard the reason.
  • Start the application with --debug, or set debug=true, and Boot prints the condition evaluation report: positive matches, negative matches, and exclusions.
  • The most common cause is @ConditionalOnMissingBean backing off because you defined a bean of that type yourself, often indirectly through another configuration class.
  • The second most common is ordering. Conditions are evaluated in auto-configuration order, so a bean defined by a later class is not yet visible to an earlier condition - which is what @AutoConfigureBefore and @AutoConfigureAfter exist to fix.
  • User configuration is always processed before auto-configuration, so your own @Bean reliably wins. That is the whole back-off contract.
  • In Boot 3 an auto-configuration is registered in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. The old spring.factories entry is ignored, and a starter that still uses it simply never loads.

Example

// Registered in:
//   src/main/resources/META-INF/spring/
//     org.springframework.boot.autoconfigure.AutoConfiguration.imports
// containing one fully-qualified class name per line.

@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnClass(AuditWriter.class)
@EnableConfigurationProperties(AuditProperties.class)
public class AuditAutoConfiguration {

    // Backs off entirely if the application declares its own AuditWriter.
    @Bean
    @ConditionalOnMissingBean
    AuditWriter auditWriter(DataSource dataSource, AuditProperties props) {
        return new JdbcAuditWriter(dataSource, props.getTableName());
    }

    // Only when the property is present AND set to true.
    @Bean
    @ConditionalOnProperty(prefix = "audit", name = "async", havingValue = "true")
    AuditDispatcher asyncDispatcher(AuditWriter writer) {
        return new AsyncAuditDispatcher(writer);
    }
}

/*
 * java -jar app.jar --debug  prints, for the class above:
 *
 *   Positive matches:
 *     AuditAutoConfiguration matched:
 *       - @ConditionalOnClass found required class AuditWriter (OnClassCondition)
 *
 *   Negative matches:
 *     AuditAutoConfiguration#asyncDispatcher:
 *       - @ConditionalOnProperty (audit.async=true) did not find property (OnPropertyCondition)
 *
 * That second block is the answer to "why is my bean missing" - no guessing needed.
 */

Spring already knows why a bean is missing; --debug prints the reason, and the answer is nearly always a back-off or an ordering problem.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Boot course, and every lesson in it is listed on the Spring Boot contents page.