Unveiling the Inner Workings of @EnableAutoConfiguration in Spring Boot
This article dissects the processing flow of Spring Boot's @EnableAutoConfiguration annotation, revealing how AutoConfigurationImportSelector and DeferredImportSelector collaborate to load, filter, and order auto‑configuration classes based on metadata, conditions, and explicit exclusions.
Introduction
In our work we often use the @EnableAutoConfiguration annotation directly or indirectly.
Today we discuss the processing logic of @EnableAutoConfiguration.
Finding the Core Class
Annotations that start with @Enable usually have an @Import that points to the implementation class. For @EnableAutoConfiguration the @Import brings in AutoConfigurationImportSelector , which is the entry point.
The class hierarchy shows that AutoConfigurationImportSelector imports AutoConfigurationImportSelector.AutoConfigurationGroup and related classes.
The Aware series are used for resource injection, and Ordered handles sorting.
DeferredImportSelector runs after all @Configuration beans, allowing it to skip already loaded auto‑configuration classes.
process
private static class DeferredImportSelectorGrouping {<br/> private final DeferredImportSelector.Group group;<br/> public Iterable<Group.Entry> getImports() {<br/> for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {<br/> this.group.process(deferredImport.getConfigurationClass().getMetadata(),<br/> deferredImport.getImportSelector());<br/> }<br/> return this.group.selectImports();<br/> }<br/>}Key steps:
ImportSelector parsing is handled in ConfigurationClassParser#processImports, where DeferredImportSelector is queued.
DeferredImportSelector handling occurs in ConfigurationClassParser#parse via deferredImportSelectorHandler.process().
AutoConfigurationImportSelector.AutoConfigurationGroup.processand selectImports are the core methods.
1. getAutoConfigurationMetadata()
public AutoConfigurationMetadata getAutoConfigurationMetadata() {<br/> if (this.autoConfigurationMetadata == null) {<br/> this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);<br/> }<br/> return this.autoConfigurationMetadata;<br/>}This loads the metadata from META-INF/spring-autoconfigure-metadata.properties.
2. getAutoConfigurationEntry()
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata meta, AnnotationMetadata am) {<br/> if (!isEnabled(am)) {<br/> return EMPTY_ENTRY;<br/> }<br/> AnnotationAttributes attributes = getAttributes(am);<br/> List<String> configurations = getCandidateConfigurations(am, attributes);<br/> configurations = removeDuplicates(configurations);<br/> Set<String> exclusions = getExclusions(am, attributes);<br/> checkExcludedClasses(configurations, exclusions);<br/> configurations.removeAll(exclusions);<br/> configurations = filter(configurations, meta);<br/> fireAutoConfigurationImportEvents(configurations, exclusions);<br/> return new AutoConfigurationEntry(configurations, exclusions);<br/>}It obtains annotation attributes, candidate configurations, removes duplicates, applies exclusions, filters with conditions, and fires import events.
getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {<br/> List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());<br/> Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories.");<br/> return configurations;<br/>}Loads factory names from META-INF/spring.factories.
filter
private List<String> filter(List<String> configurations, AutoConfigurationMetadata meta) {<br/> String[] candidates = StringUtils.toStringArray(configurations);<br/> boolean[] skip = new boolean[candidates.length];<br/> boolean skipped = false;<br/> for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {<br/> invokeAwareMethods(filter);<br/> boolean[] match = filter.match(candidates, meta);<br/> for (int i = 0; i < match.length; i++) {<br/> if (!match[i]) {<br/> skip[i] = true;<br/> candidates[i] = null;<br/> skipped = true;<br/> }<br/> }<br/> }<br/> if (!skipped) {<br/> return configurations;<br/> }<br/> List<String> result = new ArrayList<>(candidates.length);<br/> for (int i = 0; i < candidates.length; i++) {<br/> if (!skip[i]) {<br/> result.add(candidates[i]);<br/> }<br/> }<br/> return result;<br/>}Implementations such as OnClassCondition, OnBeanCondition, and OnWebApplicationCondition decide which configurations to keep.
sortAutoConfigurations
private List<String> sortAutoConfigurations(Set<String> configurations, AutoConfigurationMetadata meta) {<br/> return new AutoConfigurationSorter(getMetadataReaderFactory(), meta).getInPriorityOrder(configurations);<br/>}Sorting follows alphabetical order, then @AutoConfigureOrder, then @AutoConfigureBefore / @AutoConfigureAfter.
Summary
The core processor of @EnableAutoConfiguration is AutoConfigurationImportSelector .
AutoConfigurationImportSelector implements DeferredImportSelector .
ImportSelector parsing occurs in ConfigurationClassParser#processImports, queuing the selector for later handling.
AutoConfigurationImportSelector.AutoConfigurationGroup.processand selectImports are the focal methods. ConfigurationClassParser#doProcessConfigurationClass uses conditionEvaluator.shouldSkip(...) to apply various @Conditional annotations, enabling custom configurations to override auto‑configuration.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
