本文最后更新于 2025-11-06,文章内容可能已经过时。

SpringBoot的条件注解是实现"按需配置"的核心机制,它们允许开发者根据特定条件动态决定Bean的创建与配置的生效。所有条件注解都基于@Conditional元注解构建,通过实现Condition接口的matches()方法进行条件判断。

一、基于类存在性的条件注解

1. @ConditionalOnClass

  • 作用:当类路径上存在指定类时,条件成立

  • 属性

    • value:要检查的类的Class类型数组
    • name:要检查的类或接口的全限定名(字符串形式)
  • 典型使用场景:自动配置类中检查依赖库是否存在

  • 示例

    @Configuration
    @ConditionalOnClass({DataSource.class, EntityManager.class})
    public class JpaAutoConfiguration {
        // 当类路径存在DataSource和EntityManager时生效
    }
    

2. @ConditionalOnMissingClass

  • 作用:当类路径上不存在指定类时,条件成立

  • 属性value(与@ConditionalOnClassvalue作用相反)

  • 典型使用场景:当特定依赖不存在时才启用某个功能

  • 示例

    @Configuration
    @ConditionalOnMissingClass("com.example.MyClass")
    public class MyAutoConfiguration {
        // 当类com.example.MyClass不存在时生效
    }
    

二、基于Bean存在性的条件注解

3. @ConditionalOnBean

  • 作用:当容器中存在指定Bean时,条件成立

  • 属性

    • value:指定匹配的Bean类型(Class数组)
    • type:指定匹配的Bean类型全限定名
    • name:指定匹配的Bean名称
    • parameterizedContainer:检查泛型类型实现
    • annotation:检查被特定注解标注的Bean
    • match:匹配类型(默认MatchType.ALL,需全部存在;MatchType.ANY,存在一个即可)
  • 典型使用场景:避免重复注册Bean,或为默认Bean提供自定义覆盖

  • 示例

    @Bean
    @ConditionalOnBean(DataSource.class)
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    

4. @ConditionalOnMissingBean

  • 作用:当容器中不存在指定Bean时,条件成立

  • 属性:与@ConditionalOnBean相同,但多了:

    • ignored:匹配时要忽略的Class类型数组
    • ignoredType:匹配时要忽略的Class类型数组名称
  • 典型使用场景:提供默认Bean实现,允许用户通过自定义Bean覆盖

  • 示例

    @Bean
    @ConditionalOnMissingBean(DataSource.class)
    public DataSource defaultDataSource() {
        return new HikariDataSource();
    }
    

三、基于配置属性的条件注解

5. @ConditionalOnProperty

  • 作用:根据配置文件(如application.yml)中的属性值决定是否生效

  • 属性

    • name:配置属性名
    • havingValue:属性期望的值
    • matchIfMissing:如果属性不存在,是否视为满足条件(默认false)
  • 典型使用场景:功能开关、多环境配置切换

  • 示例

    @Configuration
    @ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")
    public class CacheConfig {
        // 当app.cache.enabled=true时加载
    }
    

四、基于Web环境的条件注解

6. @ConditionalOnWebApplication

  • 作用:当应用是Web应用时生效

  • 属性type(指定Web应用类型,如WebApplicationType.SERVLET

  • 典型使用场景:Web应用特有的配置

  • 示例

    @Configuration
    @ConditionalOnWebApplication(type = WebApplicationType.SERVLET)
    public class WebConfig {
        // 仅在Servlet Web应用中生效
    }
    

7. @ConditionalOnNotWebApplication

  • 作用:当应用不是Web应用时生效

  • 典型使用场景:非Web应用特有的配置

  • 示例

    @Configuration
    @ConditionalOnNotWebApplication
    public class NonWebConfig {
        // 仅在非Web应用中生效
    }
    

五、基于资源存在性的条件注解

8. @ConditionalOnResource

  • 作用:当指定资源存在时生效

  • 属性resources(资源路径数组)

  • 典型使用场景:检查特定配置文件是否存在

  • 示例

    @Configuration
    @ConditionalOnResource(resources = "classpath:application.properties")
    public class ResourceConfig {
        // 当application.properties存在时生效
    }
    

六、基于Java版本的条件注解

9. @ConditionalOnJava

  • 作用:根据Java版本决定是否生效

  • 属性value(指定Java版本,如JavaVersion.EIGHT

  • 典型使用场景:针对不同Java版本的特定实现

  • 示例

    @Configuration
    @ConditionalOnJava(JavaVersion.EIGHT)
    public class Java8Config {
        // 仅在Java 8及以上版本生效
    }
    

七、基于表达式的条件注解

10. @ConditionalOnExpression

  • 作用:根据SpEL表达式决定是否生效

  • 属性value(SpEL表达式字符串)

  • 典型使用场景:复杂条件判断

  • 示例

    @Configuration
    @ConditionalOnExpression("${app.feature.enabled:false}")
    public class FeatureConfig {
        // 当配置属性app.feature.enabled为true时生效
    }
    

八、其他条件注解

11. @ConditionalOnSingleCandidate

  • 作用:当指定类型在容器中只有一个候选Bean时生效

  • 属性value(Bean类型)

  • 典型使用场景:确保唯一Bean的配置

  • 示例

    @Bean
    @ConditionalOnSingleCandidate(DataSource.class)
    public DataSource dataSource() {
        return new HikariDataSource();
    }
    

九、条件注解的组合使用

条件注解可以组合使用,实现更复杂的条件判断:

@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnProperty(name = "app.database.enabled", havingValue = "true")
@ConditionalOnWebApplication
public class DatabaseConfig {
    // 仅在Web应用、存在DataSource类、且app.database.enabled=true时生效
}

十、条件注解的实现原理

条件注解的核心原理是基于Spring的@Conditional元注解,它要求实现Condition接口的matches()方法:

public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

SpringBoot中的每个条件注解都对应一个Condition实现类,例如OnClassCondition用于@ConditionalOnClassOnBeanCondition用于@ConditionalOnBean等。

总结

SpringBoot的条件注解体系非常丰富,覆盖了从类存在性、Bean存在性、配置属性、Web环境、资源存在性、Java版本到表达式判断的全方位条件判断场景。通过这些条件注解,SpringBoot实现了强大的"按需配置"能力,使得应用配置更加灵活、适应性更强,避免了不必要的资源消耗和潜在的冲突。

使用条件注解的最佳实践包括:明确条件判断逻辑、避免过度复杂的条件组合、合理使用@ConditionalOnMissingBean提供默认配置、在配置类上使用合适的条件注解等。