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
- End -
梦想是咸鱼
关注一下吧
posted @ 2021-08-09 15:31  Maggieq8324  阅读(63)  评论(0编辑  收藏  举报