Spring 中的条件注解
1、简介
本文将带你了解 Spring 中的 @Conditional
注解。它用于根据特定条件来控制 Bean 的创建和注册。
2、声明条件
首先来看看在哪些情况下可以使用条件注解。
最常见的用法是包含或排除整个配置类:
@Configuration
@Conditional(IsDevEnvCondition.class)
class DevEnvLoggingConfiguration {
}
或者是一个 Bean:
@Configuration
class DevEnvLoggingConfiguration {
@Bean
@Conditional(IsDevEnvCondition.class)
LoggingService loggingService() {
return new LoggingService();
}
}
如上,这样就可以根据特定条件(如环境类型或特定需求)来调整应用的行为。在上例中,只为开发环境初始化了额外的 LoggingService
。
另一种方式是直接在组件类上放置条件。
@Service
@Conditional(IsDevEnvCondition.class)
class LoggingService {
// ...
}
可以将上述示例应用于任何使用 @Component
、@Service
、@Repository
或 @Controller
注解声明的 Bean。
3、预定义条件注解
Spring 自带一组预定义的条件注解。
首先,看看如何根据配置的属性值来创建组件:
@Service
@ConditionalOnProperty(
value="logging.enabled",
havingValue = "true",
matchIfMissing = true)
class LoggingService {
// ...
}
第一个属性 value
指定了要匹配的配置属性。第二个属性 havingValue
定义了该条件所需的值。最后,matchIfMissing
属性告诉 Spring,如果参数缺失,是否应匹配该条件。
同样地,可以基于表达式来设定条件。
@Service
@ConditionalOnExpression(
"${logging.enabled:true} and '${logging.level}'.equals('DEBUG')"
)
class LoggingService {
// ...
}
现在,只有当 logging.enabled
配置属性设置为 true
且 logging.level
设置为 DEBUG
时,Spring 才会创建 LoggingService
。
可以应用另一个条件来检查是否创建了指定的 Bean。
@Service
@ConditionalOnBean(CustomLoggingConfiguration.class)
class LoggingService {
// ...
}
或指定类存在于 classpath 中:
@Service
@ConditionalOnClass(CustomLogger.class)
class LoggingService {
// ...
}
可以通过应用 @ConditionalOnMissingBean
或 @ConditionalOnMissingClass
注解来实现相反的行为。
此外,还可以将组件依赖于特定的Java版本。
@Service
@ConditionalOnJava(JavaVersion.EIGHT)
class LoggingService {
// ...
}
在上例中,只有当运行环境为 Java 8 时才会创建 LoggingService
。
最后,可以使用 @ConditionalOnWarDeployment
注解,仅在 War 包部署时启用 Bean:
@Configuration
@ConditionalOnWarDeployment
class AdditionalWebConfiguration {
// ...
}
注意,对于使用嵌入式 Web 服务器的应用,此条件将返回 false
。
4、自定义条件
Spring 允许我们通过创建自定义条件模板来定制 @Conditional
注解的行为。
要创建一个自定义条件模板,只需实现 Condition
接口即可:
class Java8Condition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return JavaVersion.getJavaVersion().equals(JavaVersion.EIGHT);
}
}
matches
方法告诉 Spring 条件是否通过。它有两个参数,提供了关于 Bean 初始化上下文和使用的 @Conditional
注解的元数据的信息。
如上例所示,只是检查 Java 版本是否为 8。
然后,将新条件作为属性设置到 @Conditional
注解中:
@Service
@Conditional(Java8Condition.class)
public class Java8DependedService {
// ...
}
这样,只有当 Java8Condition
类中的条件匹配时,才会创建 Java8DependentService
。
5、组合条件
对于更复杂的解决方案,可以使用 OR
或 AND
逻辑运算符对条件注解进行分组。
要使用 OR
运算符,需要创建一个继承 AnyNestedCondition
类的自定义条件。在该类中,需要为每个条件创建一个空的静态类,并用适当的 @Conditional
实现对其进行注解。
例如,创建一个需要 Java 8 或 Java 9 的条件:
class Java8OrJava9 extends AnyNestedCondition {
Java8OrJava9() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@Conditional(Java8Condition.class)
static class Java8 { }
@Conditional(Java9Condition.class)
static class Java9 { }
}
而 AND 运算符则简单得多。只需将条件分组即可:
@Service
@Conditional({IsWindowsCondition.class, Java8Condition.class})
@ConditionalOnJava(JavaVersion.EIGHT)
public class LoggingService {
}
在上例中,只有同时满足 IsWindowsCondition
和 Java8Condition
时,才会创建 LoggingService
。
6、总结
本文介绍了如何使用 Spring 中的条件注解,以及如何自定义自己的条件注解。
Ref:https://www.baeldung.com/spring-conditional-annotations