Java Spring@conditionalonproperty,如何匹配,仅当缺少

Java Spring@conditionalonproperty,如何匹配,仅当缺少,java,spring,spring-boot,Java,Spring,Spring Boot,我有两种工厂方法: @Bean @ConditionalOnProperty("some.property.text") public Apple createAppleX() {} 及 在根本没有“some.property.text”属性的情况下,第二个方法工作正常,第一个方法被忽略,这是所需的行为 如果我们将一些字符串设置为“some.property.text”-这两种方法都被认为是生成Apple对象的有效方法,这会导致应用程序失败,并出现错误“No qualification bea

我有两种工厂方法:

@Bean
@ConditionalOnProperty("some.property.text")
public Apple createAppleX() {}

在根本没有“some.property.text”属性的情况下,第二个方法工作正常,第一个方法被忽略,这是所需的行为

如果我们将一些字符串设置为“some.property.text”-这两种方法都被认为是生成Apple对象的有效方法,这会导致应用程序失败,并出现错误“No qualification bean of type”


如果我们对属性有一些价值,是否可以避免将第二种方法视为工厂方法?特别是,是否可以仅通过注释实现

您可以使用
非嵌套条件
来否定一个或多个嵌套条件。大概是这样的:

class NoSomePropertyCondition extends NoneNestedConditions {

    NoSomePropertyCondition() {
        super(ConfigurationPhase.PARSE_CONFIGURATION);
    }

    @ConditionalOnProperty("some.property.text")
    static class SomePropertyCondition {

    }

}
然后,您可以在一个bean方法上使用此自定义条件:

@Bean
@ConditionalOnProperty("some.property.text")
public Apple createAppleX() {}

@Bean
@Conditional(NoSomePropertyCondition.class)
public Apple createAppleY() {}

本着独占鳌头的精神,这里有一个更可重用的注释:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Conditional(ConditionalOnMissingProperty.MissingPropertyCondition.class)
public @interface ConditionalOnMissingProperty {

    String PROPERTY_KEYS = "propertyKeys";

    @AliasFor(PROPERTY_KEYS)
    String[] value() default {};

    @AliasFor("value")
    String[] propertyKeys() default {};

    class MissingPropertyCondition extends SpringBootCondition {
        @Override
        public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String[] keys = (String[]) metadata.getAnnotationAttributes(ConditionalOnMissingProperty.class.getName()).get(PROPERTY_KEYS);
            if (keys.length > 0) {
                boolean allMissing = true;
                for (String key : keys) {
                    String propertyValue = context.getEnvironment().getProperty(key);
                    String propertyValueList = context.getEnvironment().getProperty(key + "[0]"); //in case of list
                    allMissing &= (StringUtils.isEmpty(propertyValue) && StringUtils.isEmpty(propertyValueList));
                }
                if (allMissing) {
                    return new ConditionOutcome(true, "The following properties were all null or empty in the environment: " + Arrays.toString(keys));
                }
                return new ConditionOutcome(false, "one or more properties were found.");
            } else {
                throw new RuntimeException("expected method annotated with " + ConditionalOnMissingProperty.class.getName() + " to include a non-empty " + PROPERTY_KEYS + " attribute");
            }
        }
    }
}
当一个或多个提到的属性全部不存在时,带注释的bean或配置被激活:

@ConditionalOnMissingProperty({"app.foo.bar"})
@Configuration
public class SomeConfiguration {
  //... won't run if there is an app.foo.bar property with non-empty contents.
}

稍后,如果我在虚假结果中添加更全面的报告,我将在此处添加。

我也面临同样的问题,以下是我的解决方案:

@Bean
@ConditionalOnProperty("some.property.text")
public Apple createAppleX() {}

@Bean
@ConditionalOnProperty("some.property.text", matchIfMissing=true, havingValue="value_that_never_appears")
public Apple createAppleY() {}

很好的解决方案,对于布尔型情况,此解决方案非常干净,第一个条件为true,第二个条件为false,这样您就不必使用随机值。您缺少了
@Retention(RetentionPolicy.RUNTIME)
,我还要在这里添加
@Target({ElementType.TYPE,ElementType.METHOD})
。更重要的是,您的条件是错误的,它应该是
allMissing&=(StringUtils.isEmpty(propertyValue)&&StringUtils.isEmpty(propertyValue List))
@Bean
@ConditionalOnProperty("some.property.text")
public Apple createAppleX() {}

@Bean
@ConditionalOnProperty("some.property.text", matchIfMissing=true, havingValue="value_that_never_appears")
public Apple createAppleY() {}