Spring Boot 中的 @ConditionalOnBean 注解详解

Spring Boot 中的 @ConditionalOnBean 注解详解

    • [1. 前言](#1. 前言)
    • [2. `@ConditionalOnBean` 作用与基本用法](#2. @ConditionalOnBean 作用与基本用法)
      • [2.1 `@ConditionalOnBean` 的作用](#2.1 @ConditionalOnBean 的作用)
      • [2.2 基本用法](#2.2 基本用法)
        • [示例:当 `DataSource` Bean 存在时,才创建 `MyService` Bean](#示例:当 DataSource Bean 存在时,才创建 MyService Bean)
    • [3. `@ConditionalOnBean` 详解](#3. @ConditionalOnBean 详解)
      • [3.1 `value` 和 `type` 属性(指定 Bean 类型)](#3.1 valuetype 属性(指定 Bean 类型))
      • [3.2 `name` 属性(指定 Bean 名称)](#3.2 name 属性(指定 Bean 名称))
      • [3.3 `annotation` 属性(指定 Bean 需要标注的注解)](#3.3 annotation 属性(指定 Bean 需要标注的注解))
      • [3.4 `search` 属性(搜索范围)](#3.4 search 属性(搜索范围))
    • [4. `@ConditionalOnBean` 使用场景](#4. @ConditionalOnBean 使用场景)
      • [场景 1:按需加载数据库相关 Bean](#场景 1:按需加载数据库相关 Bean)
      • [场景 2:启用某些自动配置](#场景 2:启用某些自动配置)
      • [场景 3:可选依赖的组件](#场景 3:可选依赖的组件)
    • [5. `@ConditionalOnBean` vs `@ConditionalOnMissingBean`](#5. @ConditionalOnBean vs @ConditionalOnMissingBean)
    • [6. 结论](#6. 结论)

1. 前言

在 Spring Boot 中,条件注解(Conditional 注解) 是一种强大的功能,允许我们根据某些条件动态地注册或跳过特定的 Bean。其中,@ConditionalOnBean 是最常用的条件注解之一,它的作用是:当 Spring 容器中存在指定的 Bean 时,当前 Bean 才会被注册

本篇文章将详细介绍 @ConditionalOnBean 的使用场景、原理,并提供多个示例帮助理解。


2. @ConditionalOnBean 作用与基本用法

2.1 @ConditionalOnBean 的作用

@ConditionalOnBean 主要用于以下场景:

  • 按需加载 Bean:只有在某个 Bean 存在时,另一个 Bean 才会被创建。
  • 模块化设计 :某些功能模块需要依赖特定 Bean 才能启用,例如 仅当某个组件存在时,自动配置才会生效
  • 避免 Bean 冲突 :如果某个 Bean 依赖其他 Bean,则可使用 @ConditionalOnBean 确保它不会因缺少依赖而加载失败。

2.2 基本用法

示例:当 DataSource Bean 存在时,才创建 MyService Bean
java 复制代码
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class MyConfig {

    @Bean
    public DataSource dataSource() {
        // 这里模拟 DataSource 实例,实际可用 HikariDataSource、Druid 等
        return new FakeDataSource();
    }

    @Bean
    @ConditionalOnBean(DataSource.class)  // 仅当 DataSource 存在时,才创建 MyService
    public MyService myService() {
        return new MyService();
    }
}

class MyService {
    public MyService() {
        System.out.println("MyService 被创建");
    }
}

class FakeDataSource implements DataSource {
    // 这里可以模拟 DataSource 方法
}

执行结果

复制代码
MyService 被创建

如果 dataSource() 方法被注释掉,则 MyService 不会被创建。


3. @ConditionalOnBean 详解

@ConditionalOnBean 提供了多个属性,可以更加灵活地控制 Bean 的创建。

3.1 valuetype 属性(指定 Bean 类型)

用于指定某种类型的 Bean 存在时,当前 Bean 才会被注册。

java 复制代码
@Bean
@ConditionalOnBean(value = DataSource.class)  // 仅当 DataSource 存在时生效
public MyRepository myRepository() {
    return new MyRepository();
}

等效于:

java 复制代码
@Bean
@ConditionalOnBean(type = "javax.sql.DataSource")  // 使用全限定类名
public MyRepository myRepository() {
    return new MyRepository();
}

区别

  • value:直接使用 Class 类型,编译时检查更安全。
  • type:使用字符串,可用于避免某些类找不到(如可选依赖)。

3.2 name 属性(指定 Bean 名称)

用于 指定某个 Bean 名称是否存在 来决定当前 Bean 是否加载。

java 复制代码
@Bean
@ConditionalOnBean(name = "customBean")  // 仅当名为 customBean 的 Bean 存在时注册
public MyComponent myComponent() {
    return new MyComponent();
}

3.3 annotation 属性(指定 Bean 需要标注的注解)

可以指定某些 Bean 是否包含特定注解,如果包含,则当前 Bean 才会被注册。

java 复制代码
@Bean
@ConditionalOnBean(annotation = Repository.class)  // 仅当存在 @Repository 注解的 Bean 时生效
public MyService myService() {
    return new MyService();
}

默认情况下,@ConditionalOnBean 只会在 当前应用上下文 中查找 Bean,而不会查找 父上下文 (即 Spring Boot 的 ApplicationContext 层级)。

search 选项可以指定搜索范围:

  • ALL:在所有父子 ApplicationContext 中搜索。
  • CURRENT(默认):仅搜索当前 ApplicationContext
java 复制代码
@Bean
@ConditionalOnBean(value = DataSource.class, search = SearchStrategy.ALL) // 在所有上下文中搜索
public MyService myService() {
    return new MyService();
}

4. @ConditionalOnBean 使用场景

场景 1:按需加载数据库相关 Bean

如果应用程序中 使用了数据库 ,则提供一个 DatabaseService,否则不创建:

java 复制代码
@Bean
@ConditionalOnBean(DataSource.class)
public DatabaseService databaseService() {
    return new DatabaseService();
}

场景 2:启用某些自动配置

Spring Boot 的 spring-boot-autoconfigure 模块大量使用 @ConditionalOnBean 来控制自动配置。例如:

  • 只有当 DispatcherServlet 存在时,Spring MVC 相关的自动配置才会生效
java 复制代码
@Configuration
@ConditionalOnBean(DispatcherServlet.class)
public class MvcAutoConfiguration {
    // 仅当 DispatcherServlet 存在时,Spring MVC 配置生效
}

场景 3:可选依赖的组件

有时,某些功能是可选的,比如当 Redis 组件存在时,才创建缓存管理器:

java 复制代码
@Bean
@ConditionalOnBean(name = "redisTemplate")  // 只有当 redisTemplate 存在时才加载
public CacheManager cacheManager() {
    return new RedisCacheManager();
}

5. @ConditionalOnBean vs @ConditionalOnMissingBean

注解 作用
@ConditionalOnBean 当指定 Bean 存在时,才注册当前 Bean
@ConditionalOnMissingBean 当指定 Bean 不存在时,才注册当前 Bean

示例:

java 复制代码
@Bean
@ConditionalOnMissingBean(DataSource.class)  // 仅当 DataSource 不存在时才创建
public DataSource defaultDataSource() {
    return new DefaultDataSource();
}

6. 结论

在 Spring Boot 中,@ConditionalOnBean 可以帮助我们根据 是否存在特定 Bean动态注册 Bean ,广泛用于 按需加载、自动配置 等场景。

总结:

指定 Bean 类型@ConditionalOnBean(DataSource.class)

指定 Bean 名称@ConditionalOnBean(name = "customBean")

指定 Bean 注解@ConditionalOnBean(annotation = Repository.class)

搜索范围@ConditionalOnBean(search = SearchStrategy.ALL)

你在项目中用过 @ConditionalOnBean 吗?欢迎留言分享你的经验!🚀

相关推荐
前端付豪21 分钟前
17、自动化才是正义:用 Python 接管你的日常琐事
后端·python
我是一只代码狗25 分钟前
springboot中使用线程池
java·spring boot·后端
hello早上好38 分钟前
JDK 代理原理
java·spring boot·spring
PanZonghui41 分钟前
Centos项目部署之安装数据库MySQL8
linux·后端·mysql
PanZonghui43 分钟前
Centos项目部署之运行SpringBoot打包后的jar文件
linux·spring boot
PanZonghui43 分钟前
Centos项目部署之Java安装与配置
java·linux
Victor35644 分钟前
MySQL(119)如何加密存储敏感数据?
后端
用户3966144687191 小时前
TypeScript 系统入门到项目实战-慕课网
后端
guojl1 小时前
Dubbo SPI原理与设计精要
后端