How does Spring Boot discover auto-configuration classes, and what replaced spring.factories?
answer
- META-INF/spring/...AutoConfiguration.imports
- one FQN per line, # comments
- spring.factories = legacy key EnableAutoConfiguration
- deprecated 2.7, removed 3.0
- candidate ≠ applied (still conditional)
basics
~10 sBoot reads a list of auto-configuration class names from a file on the classpath. Since Boot 2.7/3.0 that file is META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports; the old location was META-INF/spring.factories.
solid answer
~40 sAutoConfigurationImportSelector loads candidate auto-configuration class names from a well-known resource contributed by Boot and every starter jar. Since Spring Boot 2.7 (and mandatory in 3.0) that resource is META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports — a plain text file with one fully-qualified class name per line, comments allowed with '#'. The legacy mechanism listed classes under the EnableAutoConfiguration key inside META-INF/spring.factories; Boot 2.7 deprecated it and 3.0 removed reading auto-config entries from it. Each listed class is a candidate only — it still must pass its @Conditional guards to actually contribute beans. Third-party starters ship this imports file so their auto-configurations are picked up automatically. This scan happens per-jar, so multiple jars each contribute their own file and Boot merges them.
code
java · 17 lines// In a custom starter jar:
// src/main/resources/META-INF/spring/
// org.springframework.boot.autoconfigure.AutoConfiguration.imports
//
// File contents (one FQN per line, # for comments):
// # payment feature
// com.acme.payment.PaymentAutoConfiguration
@AutoConfiguration
@ConditionalOnClass(PaymentClient.class)
public class PaymentAutoConfiguration {
@Bean
@ConditionalOnMissingBean
PaymentClient paymentClient(PaymentProperties props) {
return new PaymentClient(props.getApiKey());
}
}go deeper
Know a classpath file lists the auto-config classes; exact path is bonus.
Name the .imports path, its format, and the spring.factories migration.
Explain the selector pipeline (load, exclude, filters, event) and candidate-vs-applied.
Discuss packaging a starter, per-jar merge, and back-compat trade-offs of the 2.7→3.0 migration.
## The discovery problem Auto-configuration classes cannot be found by component scanning — they live in library jars **outside** your application's base package. Boot needs an explicit registry of candidate class names, contributed by each jar independently. That registry is a **classpath resource file**. ## The modern file (Boot 2.7+, required in 3.0+) Path: `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` Format: a plain-text file, **one fully-qualified class name per line**. Blank lines are ignored and `#` starts a comment. Example contents: ``` com.example.myfeature.MyFeatureAutoConfiguration com.example.other.OtherAutoConfiguration ``` Every starter jar can carry its own copy of this file; Boot reads all copies found on the classpath and merges the class lists. ## The legacy file (pre-2.7) Older Boot used `META-INF/spring.factories`, a Java-properties file keyed by interface/annotation name. Auto-configurations were listed under the key `org.springframework.boot.autoconfigure.EnableAutoConfiguration`: ``` org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.MyFeatureAutoConfiguration,\ com.example.OtherAutoConfiguration ``` `spring.factories` still exists and is still used for **other** Boot extension points (e.g., `ApplicationContextInitializer`, `ApplicationListener`, failure analyzers), but **auto-configuration entries** were **deprecated in Boot 2.7** and are **no longer read in Boot 3.0**. If you migrate a starter, you move the auto-config class names from `spring.factories` to the new `.imports` file. ## How the selector uses it `@EnableAutoConfiguration` imports `AutoConfigurationImportSelector`. Internally it delegates to `ImportCandidates.load(AutoConfiguration.class, classLoader)` (for the imports file) plus `SpringFactoriesLoader` history, producing the full list of candidate class names. It then: 1. removes duplicates, 2. applies `exclude`/`spring.autoconfigure.exclude` filters, 3. runs `AutoConfigurationImportFilter`s (like `OnClassCondition`) to cheaply drop candidates whose classes are absent, 4. fires an `AutoConfigurationImportEvent`, 5. hands the survivors to the context, where each class's own `@Conditional` guards make the final call. ## Being a candidate ≠ being applied A class listed in the imports file is only a **candidate**. It must still satisfy its `@ConditionalOnClass`, `@ConditionalOnMissingBean`, `@ConditionalOnProperty`, etc., to contribute beans. Listing it does not force it on. ## Gotchas - Put the class in the imports file with its **exact fully-qualified name**; a typo silently means the auto-config never loads (no error). - The file lives under `src/main/resources/META-INF/spring/` in a starter module. - Since 3.0 you must annotate the class with `@AutoConfiguration` (not just `@Configuration`) for correct ordering semantics — see the starter-authoring question. - Don't confuse this with `@ComponentScan`: auto-config classes are found via the imports file precisely because they are **not** scanned.
- Is spring.factories completely dead in Boot 3?No. It's still used for other extension points like ApplicationContextInitializer, ApplicationListener, and FailureAnalyzer. Only the auto-configuration (EnableAutoConfiguration key) entries were removed in favor of the .imports file.
- If you list a class in the imports file, is it guaranteed to run?No — it's only a candidate. Its own @Conditional guards (e.g. @ConditionalOnClass, @ConditionalOnMissingBean) still decide whether it contributes any beans.
saying these in an interview costs you the question
- Saying auto-config classes are found by @ComponentScan.
- Claiming spring.factories was entirely removed in Boot 3 (only auto-config entries were).
- Thinking the imports file is a properties file with a key (it's plain one-class-per-line).