skip to content

Walk through what AutoConfigurationImportSelector does at startup and how ordering and conditions are resolved.

level: seniorimportance: should knowfreq 40%

answer

  1. DeferredImportSelector = runs after user config
  2. load imports -> exclude -> filter -> order -> event -> register
  3. OnClassCondition filters via metadata, no bytecode load
  4. per-class @Conditional = final gate
  5. --debug -> ConditionEvaluationReport

basics

~20 s

@EnableAutoConfiguration imports AutoConfigurationImportSelector. It loads candidate classes from the imports file, drops excluded ones, filters out candidates whose trigger classes are absent, orders the rest, and registers them — each then applies its own @Conditional guards.

solid answer

~30 s

@EnableAutoConfiguration is meta-annotated with @Import(AutoConfigurationImportSelector.class), a DeferredImportSelector so it runs after regular user configuration. It (1) reads candidate FQNs from META-INF/spring/...AutoConfiguration.imports across all jars, (2) removes duplicates and applies exclude/spring.autoconfigure.exclude, (3) runs AutoConfigurationImportFilters — chiefly OnClassCondition, OnBeanCondition, OnWebApplicationCondition — to cheaply discard candidates that can't match, avoiding loading their bytecode, (4) sorts survivors using @AutoConfiguration's before/after/@AutoConfigureOrder plus @AutoConfigureBefore/@AutoConfigureAfter, and (5) fires AutoConfigurationImportEvent for reporting. Being deferred is what lets @ConditionalOnMissingBean see user beans and back off. The remaining per-class @Conditional annotations are the final gate; the ConditionEvaluationReport (visible via the 'debug' flag) explains exactly which matched and why.

code

java · 16 lines
java
// @EnableAutoConfiguration is defined roughly as:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)   // <-- the engine
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

// Ordering example on a custom auto-config:
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnClass(JdbcTemplate.class)
public class MyRepoAutoConfiguration { /* beans that need the DataSource */ }

go deeper

for a junior

Aware there's a selector that finds and applies auto-config classes.

for a middle

Name the selector and that conditions decide activation; know --debug report.

for a senior

Describe the full deferred pipeline, coarse-filter vs per-class conditions, and ordering annotations.

for a principal

Reason about startup performance (metadata-driven filtering), ordering correctness across starters, and diagnosing condition reports at scale.

## Entry point `@EnableAutoConfiguration` carries `@Import(AutoConfigurationImportSelector.class)`. This class implements `DeferredImportSelector` — an `ImportSelector` variant whose selections are processed **after** all regular `@Configuration` classes (including yours). That deferral is essential: it guarantees user-defined beans are known before auto-config conditions run, enabling correct back-off. ## Step-by-step pipeline **1. Load candidates.** `getCandidateConfigurations(...)` uses `ImportCandidates.load(AutoConfiguration.class, classLoader)` to read every `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` file on the classpath (legacy: `SpringFactoriesLoader` under the `EnableAutoConfiguration` key). Each jar contributes its list; results are merged. **2. Deduplicate + exclude.** Duplicates are removed. Then classes named in `exclude`, `excludeName`, and the `spring.autoconfigure.exclude` property are stripped out. Boot validates excluded names are real (fail-fast on typos). **3. Filter (fast, coarse).** `AutoConfigurationImportFilter` implementations run against all remaining candidates in a batch. The main ones: - `OnClassCondition` — reads each candidate's `@ConditionalOnClass`/`@ConditionalOnMissingClass` metadata (from precomputed `META-INF/spring-autoconfigure-metadata.properties`) and drops candidates whose required classes are absent — **without loading the candidate class itself**. This is a big startup optimization. - `OnBeanCondition` and `OnWebApplicationCondition` do similar coarse pre-filtering. **4. Order.** Survivors are sorted. Ordering inputs: the `before`/`after` attributes on `@AutoConfiguration`, the standalone `@AutoConfigureBefore`/`@AutoConfigureAfter`, and `@AutoConfigureOrder` (a priority number). Ordering matters because one auto-config may create a bean another wants to see (or back off from). **5. Fire events.** An `AutoConfigurationImportEvent` is published to registered `AutoConfigurationImportListener`s (the `ConditionEvaluationReport` listens here to record what was considered). **6. Register.** Surviving class names are handed back to the context as imported configuration classes. ## The final gate: per-class conditions Surviving auto-config classes are still ordinary `@Configuration`-style classes decorated with `@Conditional` annotations. As the context processes them, each condition is evaluated in full: - `@ConditionalOnClass` / `@ConditionalOnMissingClass` - `@ConditionalOnBean` / `@ConditionalOnMissingBean` - `@ConditionalOnProperty` / `@ConditionalOnMissingProperty` - `@ConditionalOnResource`, `@ConditionalOnExpression`, `@ConditionalOnWebApplication`, etc. Only when a class's (and each `@Bean` method's) conditions all match do its beans get registered. ## Why 'deferred' matters Because `AutoConfigurationImportSelector` is a `DeferredImportSelector`, all your explicit configuration is registered first. So when `@ConditionalOnMissingBean` evaluates, it sees your beans and backs off. If auto-config ran eagerly, back-off would be unreliable. ## Diagnosing it Run with `--debug` (or `debug=true`) to print the **ConditionEvaluationReport**: a 'Positive matches' / 'Negative matches' / 'Exclusions' breakdown showing precisely which auto-configurations applied and which condition failed for the rest. This is the go-to tool when 'my bean didn't get created' or 'an unexpected bean appeared.' ## Gotchas - Two-phase filtering (coarse `AutoConfigurationImportFilter` then full `@Conditional`) means a class can be dropped in phase 3 without its `@Conditional` ever running — usually invisible, but relevant when debugging metadata issues. - `spring-autoconfigure-metadata.properties` is generated at build time (annotation processor) to make phase-3 filtering fast; a stale or missing metadata file can change filtering behavior. - Ordering annotations affect **which auto-config runs first**, not user config; user config always precedes auto-config as a whole.

  • Why is AutoConfigurationImportSelector a DeferredImportSelector rather than a plain ImportSelector?
    So auto-configuration is processed after all user @Configuration, letting @ConditionalOnMissingBean/@ConditionalOnBean see user-defined beans and back off correctly.
  • How do you find out why a particular auto-configuration didn't activate?
    Start with --debug (or debug=true) to print the ConditionEvaluationReport, which lists positive/negative matches and the exact condition that failed.
  • What's the point of the AutoConfigurationImportFilter phase if per-class @Conditional runs anyway?
    It's a fast, batch pre-filter using precomputed metadata to drop impossible candidates without loading their classes, speeding startup.

saying these in an interview costs you the question

  • Saying auto-config runs before user configuration (it's deferred to run after).
  • Claiming ordering annotations control user beans vs auto-config (they order auto-configs among themselves).
  • Thinking each candidate's class bytecode is always loaded to check conditions (OnClassCondition avoids that via metadata).

context