问题
Is there any way to use @ConditionalOnProperty annotation based on multi-valued property?
Spring configuration:
@Bean
@ConditionalOnProperty(name = "prop", havingValue = "a")
public SomeBean bean1() {
return new SomeBean1();
}
@Bean
@ConditionalOnProperty(name = "prop", havingValue = "b")
public SomeBean bean2() {
return new SomeBean2();
}
and application.yaml
prop:
- a
- b
I expect that both beans: bean1 and bean2 will be registered in the spring context, but no one from them isn't registered. Is there any way to do it?
回答1:
You can use Spring Boot @ConditionalOnExpression annotation, not just in the @bean-annotated methods, but directly on classes as well:
@ConditionalOnExpression("${my.prop}")
@Component
class SomeBean1 implements SomeBean {}
@ConditionalOnExpression("!${my.prop}")
@Component
class SomeBean2 implements SomeBean {}
Having said this I personally prefer using pure Java:
@Value("${my.prop}") String myProp;
...
@Bean SomeBean someBean() {
if ("abc".equals(myProp)) {return new SomeBean1();} else {return new SomeBean2();}
}
回答2:
It looks like @ConditionalOnProperty haven't multivalued properies. In spring environment they are presented as
prop[0]=a
prop[1]=b
My solution is to make my own @Conditional extension, that is able to work with multivalued properies. Here is the example.
Annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty2 {
String name();
String value();
}
Condition:
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);
}
}
Usage:
@Bean
@ConditionalOnProperty2(name = "prop", havingValue = "a")
public SomeBean bean1() {
return new SomeBean1();
}
@Bean
@ConditionalOnProperty2(name = "prop", havingValue = "b")
public SomeBean bean2() {
return new SomeBean2();
}
来源:https://stackoverflow.com/questions/37969140/conditionalonproperty-for-multi-valued-properies