Использование языка выражений Spring для подтверждения того, что свойство (со значениями, разделенными запятыми), загруженное из файла свойств, содержит "значение"
У меня следующая проблема: у меня есть определенный класс конфигурации в весенней загрузке, который содержит bean-компоненты, которые я хотел бы создать, только если определенное свойство, имеющее список значений, содержит определенное значение.
теперь класс конфигурации выглядит примерно так:
@ConditionalOnExpression("#{'${conditions.values.options}'.contains('ScenarioOne')}")
ConfigurationForScenarioOne{
@Bean
public StudentBean getStudentBean(){
...
}
}
В файле свойств у меня было бы что-то вроде этого:
conditions.values.options=${CONDITIONS_VALUES_OPTIONS}
Затем укажите значение CONDITIONS_VALUES_OPTIONS
во время выполнения так:
-DCONDITIONS_VALUES_OPTIONS=ScenarioOne,ScenarioTwo,ScenarioFive
Причина, по которой я хочу это сделать, заключается в том, чтобы иметь возможность развернуть приложение и использовать разные bean-компоненты в зависимости от значения, заданного во время выполнения.
У меня будет несколько таких классов конфигурации, которые будут созданы на основе того, какие из этих свойств передаются. Чтобы добиться этого, я пытался полагаться на язык Spring Expression, чтобы сделать следующее:
1-Прочитать свойствоconditions.values.options
, затем преобразуйте его в список, затем проверьте, содержит ли список нужную строку конфигурации.
До сих пор я пробовал несколько выражений, включая:
@ConditionalOnExpression("#{'${conditions.values.options}'.contains('ScenarioOne')}")
и другие подобные выражения, но безуспешно. Может ли кто-нибудь помочь мне увидеть, что мне здесь не хватает?
3 ответа
Я смог получить желаемое поведение, используя это:
@ConditionalOnExpression("#{T(java.util.Arrays).asList('${conditions.values.options}').contains('ScenarioOne')}")
Итак, рассмотрим это немного в надежде помочь другим, кто может столкнуться с подобными проблемами: кажется, что spring читает свойства, разделенные запятыми, как массив, это подделка, потому что с помощью Spring boot можно сделать следующее:
Следующие два утверждения действительны:
@Value("${property.with.comma.separated.values}")
private List<String> prop;
ИЛИ
@Value("${property.with.comma.separated.values}")
private String [] prop;
теперь выражение:
"#{'${conditions.values.options}'.contains('ScenarioOne')}"
выдаст ошибку о том, что класс Array не содержит метода с именем '.contains()', поэтому мне пришлось прибегнуть к использованию выполнения некоторого метода:
T(java.util.Arrays).asList('${conditions.values.options}')
чтобы прочитать значения, разделенные запятыми, преобразуйте массив String в список, а затем выполните вызов метода.contains(..).
Я бы хотел, чтобы был более простой способ сделать это, вызов метода там кажется излишеством.
Я открыт для предложений
Альтернативой является реализация пользовательской условной аннотации.
@ConditionalOnHavingValue(property = "conditions.values.options", value = "ScenarioOne")
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnHavingValueCondition.class)
public @interface ConditionalOnHavingValue {
/**
* The property that should contain the value.
*/
String property();
/**
* The value that must be present.
*/
String value();
}
public class OnHavingValueCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
final MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(ConditionalOnHavingValue.class.getName());
if (attributes == null) {
return ConditionOutcome.noMatch("Unable to retrieve attributes from ConditionalOnHavingValue annotation");
}
final String property = (String) attributes.getFirst("property");
final String value = (String) attributes.getFirst("value");
//noinspection unchecked,DataFlowIssue
final Set<String> propertyValues = (Set<String>) context.getEnvironment().getProperty(property, Set.class);
//noinspection DataFlowIssue
if (!propertyValues.contains(value)) {
return ConditionOutcome.noMatch("Unable to find the particular value in the property");
}
return ConditionOutcome.match();
}
}
Можете ли вы попробовать записать свои значения аннотации, как это, и проверить:
@ConditionalOnExpression("#{${conditions.values.options}}.contains('ScenarioOne')")
После фигурных скобок напишите метод contains.