在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创建和配置加载。