天天看点

自定义SpringBoot Starter - @Conditional按条件装配

作者:IT食者

@Conditional是什么

@Conditional是Spring提供的用于条件装配的注解,在SpringBoot Starter中广泛使用,主要作用是控制Bean是否被容器装配。

先看源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	Class<? extends Condition>[] value();
}

@FunctionalInterface
public interface Condition {
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}           

源码很简单,@Conditional内部定义了一个Condition接口类型的数组,当数组的每一个matches方法都返回true时,Bean就会被Spring容器装配

如何使用

第一种:作为方法级注解,同@Bean一起使用

public class MyCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    return true;
  }
}           
@Configuration
public class MyConfiguration {
  @Bean
  @Conditional({MyCondition.class})
  public SmsProperties smsProperties(){
    return new SmsProperties();
  }
}           

第二种:作为类级注解,同@Component或@Configuration等一起使用

public class MyCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    return true;
  }
}           
@Configuration
@Conditional({MyCondition.class})
public class MyConfiguration {
  
}           

第三种:作为元注解,派生其它注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({MyCondition.class})
public @interface MyConditionalOnProperty {
  String value() default "";
  String key() default "";
}           
public class MyCondition implements Condition {
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    Map<String, Object> attrMap = 
        metadata.getAnnotationAttributes(MyConditionalOnProperty.class.getName());
    String key=String.valueOf(attrMap.get("key"));
    String value=String.valueOf(attrMap.get("value"));
    String systemValue=System.getProperty(key);
    return value.equals(systemValue);
  }
}           
@Configuration
public class MyConfiguration {
  @Bean
  @MyConditionalOnProperty(key = "com.v5ba.url", value = "127.0.0.1")
  public SmsProperties smsProperties(){
    return new SmsProperties();
  }
}           

官方提供了比较全面的派生注解,大多数情况下我们不需要自己实现,直接使用即可

  • @ConditionalOnJava:系统的java版本是否符合要求
  • @ConditionalOnBean:包含指定的Bean类
  • @ConditionalOnMissingBean:不包含指定的Bean类
  • @ConditionalOnExpression:符合指定的SpEL表达式
  • @ConditionalOnClass:包含指定的类
  • @ConditionalOnMissingClass:不包含指定的类
  • @ConditionalOnSingleCandidate:容器中只有一个指定的Bean,或者这个Bean是首选Bean
  • @ConditionalOnProperty:指定的property属性包含指定的值
  • @ConditionalOnResource:存在指定的资源
  • @ConditionalOnWebApplication:当前系统是Web环境
  • @ConditionalOnNotWebApplication:当前系统不是Web环境
  • @ConditionalOnjndi:JNDI存在指定的项
  • @Profile:根据不同的环境装配Bean