【问题标题】:@ConditionalOnProperty for multi-valued properies@ConditionalOnProperty 用于多值属性
【发布时间】:2023-03-23 18:41:01
【问题描述】:

有没有办法使用基于多值属性的@ConditionalOnProperty注解?

弹簧配置:

@Bean
@ConditionalOnProperty(name = "prop", havingValue = "a")
public SomeBean bean1() {
    return new SomeBean1();
}

@Bean
@ConditionalOnProperty(name = "prop", havingValue = "b")
public SomeBean bean2() {
    return new SomeBean2();
}

和 application.yaml

prop: 
 - a
 - b

我希望这两个 bean:bean1 和 bean2 都将在 spring 上下文中注册,但其中没有一个未注册。有什么办法吗?

【问题讨论】:

  • 你是说稍后当你做 context.getBean("bean1");它不起作用??
  • @Mudassar 是的,没错

标签: java spring spring-boot yaml


【解决方案1】:

看起来@ConditionalOnProperty 没有多值属性。 在 spring 环境中,它们显示为

prop[0]=a
prop[1]=b

我的解决方案是制作我自己的@Conditional 扩展,它能够处理多值属性。这是一个例子。

注释:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty2 {
    String name();
    String value();
}

条件:

class OnPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String name = attribute(metadata, "name");
        String value = attribute(metadata, "value");

        String searchName = name;
        String property = property(context, searchName);
        int i = 0;
        do {
            if (value.equals(property)) return true;
            searchName = name + '[' + i++ + ']';
        } while ((property = property(context, searchName)) != null);
        return false;
    }

    private String attribute(AnnotatedTypeMetadata metadata, String name) {
        return (String) metadata.getAnnotationAttributes(ConditionalOnProperty2.class.getName()).get(name);
    }

    private String property(ConditionContext context, String name) {
        return context.getEnvironment().getProperty(name);
    }
}

用法:

 @Bean
 @ConditionalOnProperty2(name = "prop", havingValue = "a")
 public SomeBean bean1() {
     return new SomeBean1();
 }

 @Bean
 @ConditionalOnProperty2(name = "prop", havingValue = "b")
 public SomeBean bean2() {
     return new SomeBean2();
 }

【讨论】:

  • 如果使用 Spring Boot 运行,可能需要扩展 SpringBootCondition,因为如果某些东西不能正常工作,它会提供更多的日志信息。
【解决方案2】:

您可以使用 Spring Boot @ConditionalOnExpression 注解,不仅可以在 @bean-annotated 方法中使用,还可以直接在类上使用:

@ConditionalOnExpression("${my.prop}")
@Component
class SomeBean1 implements SomeBean {}

@ConditionalOnExpression("!${my.prop}")
@Component
class SomeBean2 implements SomeBean {}

话虽如此,我个人更喜欢使用纯 Java:

@Value("${my.prop}") String myProp;
...
@Bean SomeBean someBean() {
    if ("abc".equals(myProp)) {return new SomeBean1();} else {return new SomeBean2();}
}

【讨论】:

  • 你能给我一个@ConditionalOnExpression 和多值属性的例子吗?我的意思是 @ConditionalOnExpression("${my.prop}.contains('a')")?
  • @Value 方法对我不利,因为我想在上下文中注册 bean 的集合,而不仅仅是一个。而且我事先不知道豆子的数量(这取决于属性'prop')
  • 我认为应该是@ConditionalOnExpression("'${my.prop}'.contains('a')") 或者例如@ConditionalOnExpression("'${my.prop}'= ='abc'”)。您可以使用 SpEL 支持的任何表达式。我知道您想依赖组件扫描,否则您可以在 @Configuration 类中执行所有逻辑。
  • 我个人还是更喜欢在纯 Java 中使用这个逻辑,例如: class SomeBeanManager {@Autowired void setAllOfThem(List allOfThem) {...} } 并根据您的属性。
  • 不幸的是 @ConditionalOnExpression("${my.prop}.contains('a')") 抛出异常。我不确定,但似乎弹簧条件 SpEL 不能与多值属性一起使用。我会尝试实现我自己的@Conditional 扩展来处理它。
猜你喜欢
  • 2018-07-20
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2018-02-17
  • 1970-01-01
  • 2017-06-14
  • 2020-07-22
  • 1970-01-01
相关资源
最近更新 更多