Spring 注解 `@Conditional` 与 `@ConditionalOnXxx` 具体十三种实现详解和实战

在Spring框架中,@Conditional 注解及其派生注解(如 @ConditionalOnClass, @ConditionalOnProperty 等)为开发者提供了强大的条件化配置能力。这些注解允许我们根据特定条件来决定是否加载某个配置或创建某个Bean。Spring Boot框架中进一步扩展了这些注解,提供了更多的条件判断方式。本文将详细介绍十三种与条件化配置相关的注解,并通过实战案例来说明它们的用法。

一、@Conditional 基础

@Conditional 是一个元注解,它接受一个实现了 Condition 接口的类作为参数。这个 Condition 接口定义了一个 matches 方法,用于判断条件是否满足。

实战案例

假设我们有一个名为 WindowsPlatformCondition 的条件类,用于判断当前操作系统是否为Windows。

public class WindowsPlatformCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 假设有一个方法用于检测操作系统
        return isRunningOnWindows();
    }

    private boolean isRunningOnWindows() {
        // 这里只是一个模拟,实际情况可能通过System.getProperty("os.name")等方式检测
        return false; // 示例中假设不是Windows
    }
}

@Configuration
public class PlatformSpecificConfig {

    @Bean
    @Conditional(WindowsPlatformCondition.class)
    public Service windowsService() {
        return new WindowsSpecificServiceImpl();
    }
}

二、@ConditionalOnXxx 家族

Spring Boot扩展了@Conditional,提供了更多具体的条件注解。

1. @ConditionalOnClass

当类路径上存在指定类时,条件成立。

实战案例

@Configuration
@ConditionalOnClass(SomeClass.class)
public class SomeClassConfig {
    // ...
}

2. @ConditionalOnMissingClass

当类路径上不存在指定类时,条件成立。

实战案例

@Configuration
@ConditionalOnMissingClass("javax.servlet.Servlet")
public class NonWebConfig {
    // ...
}

3. @ConditionalOnBean

当指定的Bean存在时,条件成立。

实战案例

@Configuration
public class DataSourceConfig {

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

4. @ConditionalOnMissingBean

当指定的Bean不存在时,条件成立。

实战案例

@Configuration
public class DefaultDataSourceConfig {

    @Bean
    @ConditionalOnMissingBean(DataSource.class)
    public DataSource dataSource() {
        // 创建默认数据源
        return new EmbeddedDatabaseBuilder().build();
    }
}

5. @ConditionalOnProperty

当指定的属性有指定的值时,条件成立。

实战案例

@Configuration
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
public class FeatureConfig {
    // ...
}

6. @ConditionalOnExpression

当SpEL(Spring Expression Language)表达式的结果为true时,条件成立。

实战案例

@Configuration
@ConditionalOnExpression("${environment}=='dev'")
public class DevConfig {
    // ...
}

7. @ConditionalOnJava

当Java版本满足指定条件时,条件成立。

实战案例

@Configuration
@ConditionalOnJava(JavaVersion.EIGHT)
public class Java8Config {
    // ...
}

8. @ConditionalOnJndi

当JNDI存在时,条件成立。

实战案例

@Configuration
@ConditionalOnJndi
public class JndiConfig {
    // ...
}

9. @ConditionalOnResource

当指定的资源存在时,条件成立。

实战案例

@Configuration
@ConditionalOnResource(locations = "classpath:some-resource.txt")
public class ResourceConfig {
    // ...
}

10. @ConditionalOnWebApplication

当应用是Web应用(Web环境)时,条件成立。Spring Boot 提供了两种类型:@ConditionalOnWebApplication@ConditionalOnNotWebApplication

实战案例

@Configuration
@ConditionalOnWebApplication
public class WebAppConfig {
    // ...
}

@Configuration
@ConditionalOnNotWebApplication
public class NonWebAppConfig {
    // ...
}

11. @ConditionalOnCloudPlatform

当应用运行在某个特定的云平台上时,条件成立。Spring Boot 支持多种云平台,如 Kubernetes、Cloud Foundry 等。

实战案例

@Configuration
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
public class KubernetesConfig {
    // ...
}

12. @ConditionalOnSingleCandidate

当指定的Bean在容器中只有一个时,或者同时存在多个但有一个是首选的(primary)时,条件成立。

实战案例

@Configuration
public class MyConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }

    @Bean
    @ConditionalOnSingleCandidate(MyService.class)
    public MyServiceWrapper myServiceWrapper(MyService myService) {
        return new MyServiceWrapper(myService);
    }
}

13. 自定义 @Conditional 实现

除了上述的内置条件注解,我们还可以自定义 @Conditional 的实现来满足特定需求。

实战案例

假设我们想要基于某个自定义属性来决定是否加载某个配置,我们可以创建一个自定义的 Condition 实现。

public class CustomCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 从环境中获取自定义属性
        MultiValueMap<String, String> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName());
        String customProperty = context.getEnvironment().getProperty("custom.property");

        // 检查自定义属性是否满足条件
        return "expectedValue".equals(customProperty);
    }
}

@Configuration
public class CustomConfig {

    @Bean
    @Conditional(CustomCondition.class)
    public CustomService customService() {
        return new CustomServiceImpl();
    }
}

在上面的实战案例中,我们创建了一个名为 CustomCondition 的类,它实现了 Condition 接口并覆盖了 matches 方法。在这个方法中,我们检查了一个自定义属性 custom.property 的值是否等于 expectedValue。如果等于,则返回 true,表示条件成立。然后,我们在 CustomConfig 类中使用了 @Conditional(CustomCondition.class) 注解来指定这个条件。

通过这些条件注解,我们可以更加灵活和精细地控制Spring容器中的Bean创建和配置加载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值