【问题标题】:Spring Boot: using SpEL collection selection from YAML in @ConditionalOnExpressionSpring Boot:在@ConditionalOnExpression 中使用 YAML 中的 SpEL 集合选择
【发布时间】:2022-09-27 20:53:22
【问题描述】:
我有一个带有 YAML 配置的 Spring Boot 应用程序,其中包含如下功能列表:
features:
- key: feature1
enabled: true
description: First feature
- key: feature2
enabled: false
description: Second feature
...
我想使用@ConditionalOnExpression 有条件地初始化与这些功能相关的bean,通过键识别它们。由于 \"features\" 属性是一个列表,看来我需要选择集合来执行此操作。我已经为注释的值尝试了这两个选项:
@ConditionalOnExpression(\"${features.?[key == \'feature1\'][0].enabled}\")
@ConditionalOnExpression(\"${features}.?[key == \'feature1\'][0].enabled\")
但两者都在启动时给出相同的错误:
org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: \'lcurly({)\'
如果我将表达式(不带 ${})传递给 SpelExpressionParser.parseExpression() 然后评估它(针对以编程方式构建的特征对象列表),它会按预期工作并返回 \"enabled\" 属性的值。所以表达式的结构似乎还可以,问题是我如何在@ConditionalOnExpression 中使用它。我到底做错了什么?
标签:
java
spring
spring-boot
spring-el
【解决方案1】:
${...}与SpEL无关;该语法适用于 Spring 中的属性占位符。
例如@Value("${property.foo:default}" String someProperty。
这会将someProperty 设置为property.foo(如果存在)的值,否则设置default。 (:... 部分可以省略以强制属性存在)。
【解决方案2】:
Spring SpEL 仅支持属性文件中的简单属性占位符。
如果您的属性文件和条件代码是这样的,您的 SpEL 将起作用:
features:
feature1:
enabled: true
description: First feature.
feature2:
enabled: false
description: Second feature.
@ConditionalOnExpression(
value = "#{'${features.feature1.enabled}'.equals('true')}"
)
但是如果你想把它加载为地图特征并使用地图SpEL特征;
最优雅的方法是编写 key-values as an inline JSON(使用 ' 和 " 字符以避免繁琐的转义)并使用 SpEL 解析它:
features: '{
"feature1": {"enabled":"true", "description":"..."},
"feature2": {"enabled":"false", "description":"..."}
}'
@ConditionalOnExpression(
value = "#{${features}['feature1']['enabled'].equals('true')}"
)
如果您使用了选择方法,它会看起来像这样;
@ConditionalOnExpression(
value = "#{${features}.?[key=='feature1']['feature1']['enabled'].equals('true')}"
)