sourcetip

Spring Boot bean conditional on @ConfigurationProperties value

fileupload 2023. 2. 27. 22:24
반응형

Spring Boot bean conditional on @ConfigurationProperties value

Spring Boot gives us typed configuration objects using the @ConfigurationProperties annotation. One of the advantages is getting property name completion in the IDE for free when using the Spring Boot annotation processor. Another would be: validation.

Now, I'd like to make a bean conditional on the value of a property. Actually, I have two implementations of an interface and this property tells me which one should be used. I could implement it like this:

ImplementationA.java

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

ImplementationB.java

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

application.yml

foo:
  bar: "a"

However, I'd then lose the advantage of typed configuration. So I'd like to declare this property in a @ConfigurationProperties object:

FooProperties.java

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

    private String bar;


    public String getBar() { ... }

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

This would still work, but when I declare a default value for bar in this class, it would obviously not be picked up by @ConditionalOnProperty as this annotation operates against the Environment directly (as designed). So perhaps it'd be best not to mix these concepts.

So the question is...

Would there be a way to have a conditional bean based on a value in a @ConfigurationProperties object? Preferable using some @Conditional annotation and without creating a @Configuration bean, as that would mean boilerplate code.

It might not be as sexy but a potential solution could be to Autowire your Configuration into a SomeInterfaceConfiguration that creates provides the service implementation based on the FooProperties.

i.e.

@Configuration
public class SomeInterfaceConfiguration {

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

Another option is to use profiles but it is different to your desired solution. i.e. Have a default implementation.

@Component
public class ImplementationA 

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

As proposed here, you could create the ConfigurationProperties object manually in your @Conditional like this:

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

ReferenceURL : https://stackoverflow.com/questions/49153632/spring-boot-bean-conditional-on-configurationproperties-value

반응형