Использование языка выражений 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.

Другие вопросы по тегам