Spring 源码系列(21): 自动配置原理与 AutoConfigurationImportSelector
阅读前提示第 20 篇知道EnableAutoConfiguration靠AutoConfigurationImportSelector批量导入配置类。本篇把这个「发动机」拆开——它从哪读配置、如何按条件过滤、如何排序以及你的Bean为什么能覆盖自动配置。这是 Boot 面试的「压轴题」。一、引子自动配置到底「自动」在哪你没写DataSource、没写DispatcherServlet但引入spring-boot-starter-web它们就出现了。秘密在于AutoConfigurationImportSelector在容器启动的invokeBeanFactoryPostProcessors阶段第 5 篇第 5 步把一批xxxAutoConfiguration类导入容器而这些类用BeanConditional声明了默认组件。二、源码追踪Selector 如何选配置2.1 入口DeferredImportSelector 接口AutoConfigurationImportSelector实现DeferredImportSelector所以它的导入延迟到所有其他配置处理完之后——保证你的Bean先注册自动配置后评估这是「用户配置优先」的基础。2.2 读取候选配置// AutoConfigurationImportSelector.javaOverridepublicString[]selectImports(AnnotationMetadataannotationMetadata){if(!isEnabled(annotationMetadata))returnNO_IMPORTS;AutoConfigurationEntryautoConfigurationEntrygetAutoConfigurationEntry(annotationMetadata);returnStringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}protectedAutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadatametadata){// ① 从 META-INF/spring.factories或 .imports读取所有自动配置类名ListStringconfigurationsgetCandidateConfigurations(metadata,attributes);// ② 去重configurationsremoveDuplicates(configurations);// ③ 按 AutoConfigureBefore/After/Order 排序configurationssort(configurations,autoConfigurationMetadata);// ④ 按 exclude 属性、Conditional 过滤configurationsfilter(configurations,autoConfigurationMetadata);returnnewAutoConfigurationEntry(configurations,exclusions);}2.3 配置从哪读Boot 2.7 变化protectedListStringgetCandidateConfigurations(...){// 旧版META-INF/spring.factories 的 EnableAutoConfiguration 键// 新版(Boot2.7)META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsListStringconfigurationsImportCandidates.load(AutoConfiguration.class,getBeanClassLoader()).getCandidates();returnconfigurations;}⚠️ 版本差异Boot 2.7 起官方逐步废弃spring.factories的自动配置写法改推AutoConfiguration.imports纯类名清单但 2.7 仍兼容spring.factories。Boot 3 则完全移除spring.factories自动配置。2.4 Conditional 过滤条件评估filter最终落到ConditionEvaluator.shouldSkip评估每个xxxAutoConfiguration上的条件注解ConditionalOnClassclasspath 存在某类才生效ConditionalOnMissingBean容器中还没有某 Bean 才生效这就是你自定义Bean能覆盖它的原因ConditionalOnProperty配置项匹配才生效ConditionalOnWebApplication是 Web 应用才生效Configuration(proxyBeanMethodsfalse)ConditionalOnClass({DataSource.class,EmbeddedDatabaseType.class})ConditionalOnMissingBean(typeio.r2dbc.spi.ConnectionFactory)// 用户没配才用自动的EnableConfigurationProperties(DataSourceProperties.class)publicclassDataSourceAutoConfiguration{...}三、为什么你的 Bean 能覆盖自动配置核心机制 DeferredImportSelector延迟导入ConditionalOnMissingBean你的Bean在普通配置阶段先注册自动配置类延迟导入评估ConditionalOnMissingBean时发现「用户已配跳过」结果用户 Bean 生效自动配置退让。 结论Boot 的「约定优于配置」 默认给你配好但只要你显式声明同类型 Bean就自动让位。这是最优雅的扩展点。四、自动配置加载与过滤流程图五、常见误区误区正解自动配置类全部无条件注册错经Conditional过滤多数按需生效你的 Bean 一定覆盖自动配置仅当自动配置类标了ConditionalOnMissingBean同类型时Boot 2.7 还用 spring.factories 自动配置兼容但官方推荐迁移到AutoConfiguration.importsDeferredImportSelector 没特殊作用它让自动配置延迟导入保证用户 Bean 优先自动配置类在 refresh 之前就生效在invokeBeanFactoryPostProcessors阶段第5步导入属容器启动中 面试题自测AutoConfigurationImportSelector从哪读自动配置类Boot 2.7 的配置清单文件与旧版spring.factories有何不同自动配置类如何按条件过滤列举 4 个Conditional为什么用户的Bean能覆盖自动配置DeferredImportSelector的作用自动配置类上常见的ConditionalOnMissingBean解决了什么问题 Debug 小技巧在AutoConfigurationImportSelector.filter断点观察configurations列表从「几百个候选」被过滤到「实际生效的几十个」再在OnBeanCondition.getMatchOutcome断点看ConditionalOnMissingBean如何判定你的 Bean 已存在而跳过自动配置。下一篇预告第 22 篇条件注解Conditional全家桶——ConditionalOnClass/ConditionalOnMissingBean/ConditionalOnProperty等的底层Condition实现以及如何自定义条件注解。如果这篇对你有帮助欢迎点赞 · 收藏 · 关注三连支持。Spring 源码系列共 30 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。