Condition注解在BeanDefinition解析阶段判断,而非实例化时;其依据是当前已注册的BeanDefinition列表,而非运行时Bean实例。

Condition 注解的判断时机在 BeanDefinition 解析阶段
Condition 注解(如 @ConditionalOnBean、@ConditionalOnMissingBean)不是在 Bean 实例化时才起作用,而是在 Spring 容器解析配置类、注册 BeanDefinition 的阶段就完成判断。这意味着:它看到的不是“运行时有没有这个 Bean”,而是“当前已注册的 BeanDefinition 列表里有没有对应类型或名称的定义”。
关键点在于:ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry() 是入口,之后调用 processConfigBeanDefinitions(),再进入 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions() —— 所有 @Conditional 逻辑都在这里批量执行。
- 如果 A 配置类依赖
@ConditionalOnBean(B.class),但 B 的@Configuration类还没被 parser 解析到,A 就会跳过 -
@ConditionalOnClass检查的是 classpath 路径,不涉及加载顺序,但@ConditionalOnBean和@ConditionalOnMissingBean高度敏感于解析先后 - 哪怕 B 的 Bean 是通过
@Bean方法定义在另一个配置类里,只要那个配置类没被 load,条件就不成立
自动配置类的排序规则直接影响 Condition 结果
Spring Boot 并不会按 classpath 扫描顺序或文件名字母序加载自动配置类,而是通过三类机制控制优先级:
-
@AutoConfigureOrder(value = Ordered.HIGHEST_PRECEDENCE):数值越小越靠前,仅影响同一批次导入的配置类 -
@AutoConfigureBefore(DataSourceAutoConfiguration.class)/@AutoConfigureAfter:显式声明前后依赖,比@AutoConfigureOrder更强 - 默认无注解时,Spring Boot 2.7+ 使用内部拓扑排序(基于条件依赖图),但该行为不稳定,不建议依赖
例如你写了一个自定义 MyDataSourceConfiguration,想覆盖官方 DataSourceAutoConfiguration,只加 @ConditionalOnMissingBean(DataSource.class) 不够——必须确保它在官方类之前被解析,否则官方类先注册了 DataSource,你的条件直接失效。
为什么 @ConditionalOnMissingBean 覆盖失败?根本不是注解写错了
最常见的“自定义配置不生效”,90% 是因为加载顺序反了,而不是 @ConditionalOnMissingBean 本身有问题。它的语义很明确:“当前容器中还没有这个 Bean 的定义”。但它无法预判后续会不会有别的配置类来注册。
- 官方自动配置类(如
DataSourceAutoConfiguration)通常没有@AutoConfigureBefore,默认排在中间位置 - 你的自定义配置类如果放在
src/main/java下、被@ComponentScan扫到,它属于“用户配置”,默认比自动配置更晚加载 - 解决方案只有两个:要么用
@AutoConfigureBefore强制提前;要么把自定义配置写成 Starter,在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中显式前置声明
别试图用 @Primary 或 @Bean(name = "xxx") 绕过这个问题——@ConditionalOnMissingBean 在 BeanDefinition 阶段就筛掉了整个配置类,后面根本没机会走到实例化那步。
调试加载顺序最有效的手段是开启 DEBUG 日志
在 application.properties 中加一行:logging.level.org.springframework.boot.autoconfigure=DEBUG,启动时你会看到类似这样的输出:
o.s.b.a.AutoConfigurationImportSelector : Auto-configuration classes to be imported: [org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, com.example.MyDataSourceConfiguration]
但这只是“计划加载列表”,不代表执行顺序。真正要看执行流,得配合断点打在 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(),观察 configClasses 的迭代顺序——这个顺序才是 Condition 判断的真实上下文。
注意:Spring Boot 3.x 的 AutoConfiguration.imports 文件内容是纯文本路径列表,顺序即加载顺序;而 2.x 的 spring.factories 是 Properties 格式,key 无序,value 列表顺序才有效,但不同 ClassLoader 可能打乱顺序,所以不能假设它稳定。
复杂点在于,同一个配置类里多个 @Bean 方法之间也有隐式顺序依赖,而 Condition 注解对这种局部顺序完全不可见——它只看全局 BeanDefinition 注册状态。

















