Spring|@Conditional

场景需求引入

有个新的需求功能模块,需要对内部的计算引擎进行监控统计

在消费端(读取内存记录数据持久化)可以获取系统配置,选择创建和不创建某些调度任务来对内存的监控数据进行消费

但是在内存数据的生产者端,如果不进行特殊处理,就会出现没有消费但是每次业务操作还会对内存中维护的统计数据不断更新,造成资源浪费

因此想到将内存中维护的统计数据类注入到 Spring 容器中,通过读取配置文件,来动态注册到 Spring 容器中,在生产消息的时候,只需要额外进行判断 bean 是否为空即可

简单使用

自定义条件

Spring 提供了 Condition 接口,可以实际这个接口来自定义业务需要的条件

之后在需要条件注册的 Bean 类上,除了打上 @Component 外,再打上 @Conditonal(自定义条件.class)

1
2
3
4
5
6
7
8
public class ComputeCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 返回true或false,决定是否注册Bean
return true;
}
}
1
2
3
4
5
@Component
@Conditional(ComputeCondition.class)
public class MonitorMemDataModel {
//业务定义的内存数据模型
}

只有当ComputeCondition返回true时,MonitorMemDataModel才会被注册

组合条件

有的时候根据不同业务场景,条件也不止简单的一个,可能是复杂组合条件

但是再怎么复杂本质上也都是 | 或是 & 的排列组合

对此 Spring 分别为我们提供了 AnyNestedConditionAllNestedCondition 类来实现复杂业务条件组合

1
2
3
4
5
6
7
8
9
10
11
12
public class AOrBCondition extends AnyNestedCondition {
public AOrBCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}

@Conditional(ConditionA.class)
static class ConditionA {}

@Conditional(ConditionB.class)
static class Condition2 {}

}

这里构造函数中传递给父类的一个枚举需要注意:

  • 如果这个条件修饰的是配置类,目的是为了条件被解析使配置类动态注入,则需要传递 ConfigurationPhase.PARSE_CONFIGURATION
  • 如果这个条件修饰的是普通的Bean,目的是为了条件被解析控制普通的类动态注入,则需要传递ConfigurationPhase.REGISTER_BEAN

上面我们自定义的组合条件,效果就是 A | B 生效,那么就注册对应这个条件修饰的 Bean 到容器中

Spring 内置条件

Spring框架提供了多种内置的条件类,如@ConditionalOnProperty@ConditionalOnClass@ConditionalOnMissingBean

比较常用的是

1
@ConditionalOnProperty(name = "my.property", havingValue = "true")

实际使用场景

根据项目全局环境条件

1
2
3
4
5
6
7
public class DevCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().acceptsProfiles("dev");
}
}

类路径下是否存在某个类条件

1
2
3
4
5
6
7
8
9
@Configuration
public class AppConfig {

@Bean
@ConditionalOnClass(name = "com.example.MyClass")
public MyBean myBean() {
return new MyBean();
}
}

组合配置文件具体值

1
@ConditionalOnProperty(name = "my.property", havingValue = "true")

指定Bean存在与否条件

1
2
3
4
5
6
7
8
9
@Configuration
public class AppConfig {

@Bean
@ConditionalOnBean(name = "myDependencyBean")
public MyBean myBean() {
return new MyBean();
}
}

Spring|@Conditional
http://example.com/2024/11/11/Spring-Conditional/
作者
Noctis64
发布于
2024年11月11日
许可协议