Skip to content
章节导航

SpringBoot 条件注解的扩展

包路径:org.springframework.boot.autoconfigure.condition

注解说明
@ConditionalOnProperty根据特定的属性进行条件注入
@ConditionalOnBeanIOC 容器中存在指定的 Bean 进行条件注入
@ConditionalOnMissingBeanIOC 容器中不存在指定的 Bean 进行条件注入
@ConditionalOnClassJVM 中存在指定的 Class 进行条件注入

@ConditionalOnProperty

常用的条件化配置注解,它根据配置文件中的属性值来决定是否创建 Bean 或启用配置。

java
// spring.datasource.type=com.zaxxer.hikari.HikariDataSource 时触发
@Configuration
@ConditionalOnProperty(prefix = "spring.datasource", name = "type", havingValue = "com.zaxxer.hikari.HikariDataSource")
public class FlyHikariDataSourceAutoConfiguration {

    private final IDataSourceDecrypt dataSourceDecrypt;

    public FlyHikariDataSourceAutoConfiguration(IDataSourceDecrypt dataSourceDecrypt) {
        this.dataSourceDecrypt = dataSourceDecrypt;
    }


    @Bean
    @Primary
    public FlyHikariDataSourceWrapper hikariDataSourceConfiguration() {
        return new FlyHikariDataSourceWrapper(dataSourceDecrypt);
    }

}

@ConditionalOnBean

基于其他 Bean 的存在与否进行条件化配置的核心注解。它实现了 Bean 之间的依赖关系和条件化创建。

java
// 当某种类型的 Bean 存在时,当 RedissonClient 类型的 Bean 存在时
@Bean
@ConditionalOnBean(RedissonClient.class) 
public SlidingWindowRateLimiter slidingWindowRateLimiter(RedissonClient redisson) {
    return new SlidingWindowRateLimiter(redisson);
}

// 当某个 Bean 存在时才创建当前 Bean,当 dataSource 存在时
@Bean
@ConditionalOnBean(name = "dataSource") 
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
    System.out.println("创建JdbcTemplate,因为DataSource存在");
    return new JdbcTemplate(dataSource);
}

// 当多个 Bean 都存在时
@Bean
@ConditionalOnBean({DataSource.class, TransactionManager.class})
public TransactionalService transactionalService() {
    System.out.println("创建TransactionalService,因为DataSource和TransactionManager都存在");
    return new TransactionalService();
}

@ConditionalOnMissingBean

用于避免 Bean 重复定义和提供默认实现的核心注解。它检查容器中是否已存在某个 Bean,如果不存在才创建。

java
// 最简单的用法:当指定类型的 Bean 不存在时才创建
@Bean
@ConditionalOnMissingBean  // 没有参数,检查当前返回类型
public DataSource dataSource() {
    System.out.println("创建默认数据源(因为没有其他 DataSource Bean)");
    return new EmbeddedDatabaseBuilder()
       .setType(EmbeddedDatabaseType.H2)
       .build();
}
    
// 指定类型:当 DataSource 类型的 Bean 不存在时才创建
// 如果在其他实现了 DataSource 接口,并注册成为 Bean 时将不生效
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource defaultDataSource() {
        System.out.println("创建默认 DataSource");
        return DataSourceBuilder.create().build();
}
    
// 指定名称:当指定名称的 Bean 不存在时才创建
// 如果在其他地方创建了名为 customDataSource 的 Bean 时将不生效
@Bean
@ConditionalOnMissingBean(name = "customDataSource")
public DataSource applicationDataSource() {
    System.out.println("创建应用数据源(因为 customDataSource 不存在)");
    return DataSourceBuilder.create()
        .url("jdbc:h2:mem:appdb")
        .build();
}
    
// 多个条件:当多个Bean都不存在时才创建
@Bean
@ConditionalOnMissingBean({DataSource.class, JdbcTemplate.class})
public DatabaseManager databaseManager() {
    System.out.println("创建 DatabaseManager(因为 DataSource 和 JdbcTemplate 都不存在)");
    return new DatabaseManager();
}

@ConditionalOnMissingBean 是 Spring Boot 自动配置的核心,它确保了框架可以提供合理的默认配置,同时允许开发者完全自定义。正确使用这个注解可以大大简化配置,避免冲突,并创建灵活的、可扩展的应用程序架构。

@ConditionalOnClass

根据类路径上是否存在特定类来决定是否创建 Bean 或启用配置的核心注解。它是实现自动配置和条件化依赖的关键。

java
// 最简单的用法:检查单个类是否存在
@Bean
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public RedisService redisService() {
    System.out.println("创建Redis服务(因为Jedis类存在)");
    return new RedisService();
}
    
// 检查多个类:所有类都存在才创建
@Bean
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
public DatabaseService databaseService() {
    System.out.println("创建数据库服务(DataSource和JdbcTemplate都存在)");
    return new DatabaseService();
}
    
// 使用Class对象(编译时检查)
@Bean
@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
public ObjectMapper objectMapper() {
    System.out.println("创建ObjectMapper(Jackson2ObjectMapperBuilder存在)");
    return new ObjectMapper();
}

@Profile

用于环境隔离和条件化配置的核心注解。它根据激活的 Profile 来决定是否注册 Bean 或启用配置类。

java
@Bean
@ConditionalOnMissingBean
@Profile({"pro","prod"})
public SmsService smsService() {
    SmsServiceImpl smsService = new SmsServiceImpl();
    return smsService;
}

@Bean
@ConditionalOnMissingBean
@Profile("dev")
public SmsService mockSmsService() {
    MockSmsServiceImpl smsService = new MockSmsServiceImpl();
    return smsService;
}

@Bean
@Profile("!prod")  // 非生产环境
public SmsService debugService() {
    System.out.println("创建调试服务(非生产环境)");
    DebugSmsServiceImpl smsService = new DebugSmsServiceImpl();
    return smsService;
}