跳转到内容

自动装配与 imports

自动装配把“类路径上可能需要的配置”变成候选集合,再交给条件系统决定是否真正注册 Bean。

先给答案:自动配置是“候选配置 + 条件筛选”,不是无条件替用户创建所有 Bean

Section titled “先给答案:自动配置是“候选配置 + 条件筛选”,不是无条件替用户创建所有 Bean”

Boot 先从 imports 文件获得候选自动配置类,再通过条件判断决定哪些配置可以进入容器。候选与生效是两个阶段:一个 starter 提供候选,classpath、属性、Bean 是否存在和 Web 环境共同决定最终结果。

使用 imports 文件能把候选列表变成可索引、可排序、可诊断的元数据,而不是运行时扫描整个 classpath。排查自动配置时,应该依次看候选是否加载、条件是否匹配、用户 Bean 是否触发 @ConditionalOnMissingBean 的回退,以及最终 Bean 是否在 refresh 时创建。

@EnableAutoConfiguration
│
▼
AutoConfigurationImportSelector#selectImports
├─► getCandidateConfigurations
├─► getExclusions
├─► fire import event
└─► AutoConfigurationGroup.selectImports
└─► sort + return configuration names
  • AutoConfigurationImportSelector 在 core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java:78 实现 DeferredImportSelector。
  • selectImports() 在 :119 取得自动配置入口。
  • 候选配置由 getCandidateConfigurations() 在 :200 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。
  • 排除集合由 getExclusions() 在 :247 处理,非法排除在 :230 被校验。
  • 分组器 AutoConfigurationGroup 在 :431,先在 process() :467 收集配置,再在 selectImports() :489 排序。
  • 排序前移除全局排除项,关键逻辑在 :501。
  • 测试中的 imports 文件位于 core/spring-boot-autoconfigure/src/test/resources/META-INF/spring/...AutoConfiguration.imports。
  • 自动配置不会等价于无条件导入,最终是否生效仍取决于 @Conditional。

替代方案:扫描所有包中的 @Configuration 类。 为什么不行:启动时扫描范围大、候选边界不稳定,还会把不应暴露的内部配置带入容器。 证据:候选发现集中在 getCandidateConfigurations(),由模块显式声明入口,再由条件和排序完成决策。

场景 现象 原因 规避
配置类未写入 imports 自动配置完全不出现 候选发现阶段没有名字 检查资源路径和构建产物
自动配置顺序错误 Bean 定义覆盖或缺失 依赖配置尚未先注册 使用 Boot 的 before/after 排序语义
排除类名错误 启动失败或排除无效 handleInvalidExcludes 校验失败 使用实际配置类全名

显式候选清单比全量扫描更适合插件系统:它控制边界,条件负责环境适配,排序负责依赖关系,三者职责清晰。

面试锚点

  • AutoConfiguration.imports 与旧式 spring.factories 的职责差异是什么?
  • 自动配置为什么是 deferred import?
  • 用户 Bean 如何阻止默认自动配置?