@ConditionalOnBean 就是它们的反面镜:“只有当某个特定的 Bean 已经存在于容器中时,我才会被实例化。”

这通常用于依赖性配置。例如:只有当你配置了“数据库连接池(DataSource)”,我才去加载“事务管理器(TransactionManager)”。


1. 核心逻辑

它的判断标准是:“容器里有没有那个谁?有的话,我也加入;没有的话,我也消失。”


2. 为什么要用它?

  1. 强依赖关系:某些功能必须建立在另一个功能存在的基础上。

  2. 避免异常:如果依赖的 Bean 不存在,直接创建当前 Bean 可能会导致空指针或启动报错。通过这个注解,Spring 会优雅地跳过这个 Bean 的创建。

  3. 插件式开发:当用户引入了某个可选的 SDK(比如 Redis),你的组件才自动激活相关的缓存功能。


3. 语法与参数

@Bean
@ConditionalOnBean(DataSource.class)
public MyDatabaseHelper myHelper(DataSource ds) {
    return new MyDatabaseHelper(ds);
}
  • value / type: 检查是否存在指定类型的 Bean(最常用)。

  • name: 检查是否存在指定名称(ID)的 Bean。

  • annotation: 检查是否有 Bean 标注了特定的注解。


4. 实战:联动配置

假设你正在写一个监控系统,只有当用户定义了 MeterRegistry(用于指标收集)时,你才开启“自动上报数据”的功能。

@Configuration
public class MetricsAutoConfiguration {

    // 只有当容器里已经有 MeterRegistry 这个 Bean 了,
    // 才会创建 MetricsReporter
    @Bean
    @ConditionalOnBean(MeterRegistry.class)
    public MetricsReporter metricsReporter(MeterRegistry registry) {
        return new MetricsReporter(registry);
    }
}

5. ⚠️ 最关键的注意事项:加载顺序

这是 @ConditionalOnBean 最容易让人掉头发的地方。

Bean 的扫描是有顺序的。 如果 Spring 扫描到 @ConditionalOnBean(A.class) 时,A 还没有被定义(虽然它可能在后面的配置类里),Spring 也会判定为“不存在”,从而跳过当前 Bean。

黄金法则:

  1. 尽量在自动配置类(Auto-configuration)中使用:官方建议将其用于外部库的自动配置,因为 Spring Boot 会在所有用户定义的 @Component 加载完后,才去处理这些自动配置。

配合 @AutoConfigureAfter 使用:如果你明确知道依赖哪个配置类,可以用这个注解强制规定先后顺序。

@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class) // 确保在数据源配置完后再动
public class MyJdbcConfig {
    @Bean
    @ConditionalOnBean(DataSource.class)
    public MyTool myTool() { ... }
}

6. 三大注解对比表

注解

逻辑

场景

@ConditionalOnMissingBean

没有 A,才加载我

提供默认实现,允许用户覆盖。

@ConditionalOnProperty

配置项为 X,才加载我

功能开关,环境切换。

@ConditionalOnBean

有了 A,才加载我

插件扩展,存在依赖关系的组件。


这三个注解基本涵盖了 Spring Boot 自动配置 90% 的场景。