弹簧靴豆以@ConfigurationProperties值为条件

2022-09-01 16:17:10

Spring Boot使用注释为我们提供了类型化的配置对象。其中一个优点是在使用 Spring Boot 注释处理器时,在 IDE 中免费获得属性名称完成。另一个是:验证。@ConfigurationProperties

现在,我想以属性的价值为条件。实际上,我有两个接口的实现,这个属性告诉我应该使用哪一个。我可以像这样实现它:

实施A.java

@Component
@ConditionalOnProperty(name = "foo.bar", havingValue = "a")
public class ImplementationA implements SomeInterface { ... }

实现B.java

@Component
@ConditionalOnProperty(name = "foo.bar", havingValue = "b")
public class ImplementationB implements SomeInterface { ... }

应用程序.yml

foo:
  bar: "a"

但是,我将失去类型化配置的优势。所以我想在一个对象中声明这个属性:@ConfigurationProperties

产品.java

@ConfigurationProperties(prefix = "foo")
public class FooProperties {

    private String bar;


    public String getBar() { ... }

    public void setBar(String bar) { ... }
}

这仍然有效,但是当我在此类中声明默认值时,它显然不会被拾取,因为此注释直接针对(按设计)操作。因此,也许最好不要混淆这些概念。bar@ConditionalOnPropertyEnvironment

所以问题是...

有没有办法基于对象中的值来创建条件bean?最好使用一些注释并且不创建bean,因为这意味着样板代码。@ConfigurationProperties@Conditional@Configuration


答案 1

它可能不那么性感,但一个潜在的解决方案可能是将你的配置自动连接到SomeInterfaceConfiguration中,该配置创建基于FooProperties提供服务实现。

@Configuration
public class SomeInterfaceConfiguration {

    @Bean
    @Autowired
    public SomeInterface someInterface(FooProperties fooProperties){
        if("a".equals(fooProperties.getBar()){
            return SomeInterfaceImplementationA();
        } else {
            return SomeInterfaceImplementationB();
        }
    }
}

另一种选择是使用配置文件,但它与所需的解决方案不同。即有一个默认的实现。

@Component
public class ImplementationA 

@Profile("b")
@Primary
@Component
public class ImplementationB

答案 2

按照此处的建议,您可以在@Conditional中手动创建 ConfigurationProperties 对象,如下所示:

import org.springframework.boot.context.properties.bind.Binder
...
YourConfigurationPropertiesClass config = Binder.get(context.getEnvironment())
.bind("your.properties.prefix", YourConfigurationPropertiesClass.class).orElse(null);

推荐