Spring - 关于条件注解的一些理解
前言
@Conditional是Spring4提供的注解,它可以根据条件判断是否将Bean注册到容器中,源码如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
简单示例
举一个简单的例子,如何根据当前操作系统来进行对象实例化
- 接口
public interface SystemInter {
String get();
}
- 实现类
public class Linux implements SystemInter {
@Override
public String get() {
return "System's Linux";
}
}
public class Windows implements SystemInter {
@Override
public String get() {
return "System's windows";
}
}
- 控制器
public class TestController {
@Autowired
private SystemInter systemInter;
@GetMapping(value = "/system")
public String getSystem(){
return systemInter.get();
}
}
上述代码用于表示操作系统的两个对象,问题来了,如何根据操作系统进行相应的对象实例化,在控制器中注入呢?
这里就可以用到@Conditional注解,通过实现Condition接口重写方法来自定义match规则,Condition接口需要实现matches方法,返回true则注入bean,false则不注入。
- 条件类
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取配置文件中system.condition的属性
String name = conditionContext.getEnvironment().getProperty("system.condition");
return "linux".equalsIgnoreCase(name);
}
}
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取配置文件中system.condition的属性
String name = conditionContext.getEnvironment().getProperty("system.condition");
return "windows".equalsIgnoreCase(name);
}
}
- application.properties的配置,配置操作系统为windows
system.condition = windows
- 创建SystemConfiguration 类,用于配置两个实例的注入
@Configuration
public class SystemConfiguration {
@Bean
@Conditional(LinuxCondition.class)
public SystemInter linux() {
return new Linux();
}
@Bean
@Conditional(WindowsCondition.class)
public SystemInter windows() {
return new Windows();
}
}
-
由上述代码可以看出,我们给两个操作系统对象分别建立的对应的条件类,并通过配置文件中的system.condition属性来判断是否实例化。
-
访问接口结果如下,可以看出,我们从配置文件读取操作系统类型并实例化了windows对象。
- 切换application.properties的操作系统配置为linux
system.condition = linux
- 访问结果如下:
- 这是个简单的例子,却体现了Spring的策略模式(根据环境或者条件的不同选择不同的算法或者策略来完成该功能)
- 注:以上的示例将@Conditional标注在方法上,而@Conditional标注在类上可以判断该配置类中的所有Bean是否注入。
内置的条件注解
注解 | 条件 |
---|---|
@ConditionalOnBean | 当SpringIoC容器内存在指定Bean的条件 |
@ConditionalOnMissingBean | 当SpringIoC容器内不存在指定Bean的条件 |
@ConditionalOnClass | 当SpringIoC容器内存在指定Class的条件 |
@ConditionalOnMissingClass | 当SpringIoC容器内不存在指定Class的条件 |
@ConditionalOnProperty | 指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径是否有指定的值 |
@ConditionalOnWebApplication | 当前项目是Web项目的条件 |
@ConditionalOnNotWebApplication | 当项目不是Web项目的条件 |
@ConditionalOnExpression | 基于SpEL表达式作为判断条件 |
@ConditionalOnJava | 基于JVM版本作为判断条件 |
@ConditionalOnJndi | 在JNDI存在时查找指定的位置 |
@ConditionalOnSingleCandidate | 当指定Bean在SpringIoC容器内只有一个,或者虽然有多个但是指定首选的Bean |