有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Spring YAML配置中避开SpEL美元符号?

在SpringYAML配置文件中,我需要一个参数,如

csv:
  file:
    pattern: /some/path/${app-name}.csv

其中${app-name}在运行时被Java代码动态替换,我不希望Spring在启动时替换它

为了实现这一点,我需要转义$字符,这样Spring就不会将其解释为SpEL

以下答案在YAML中不适用:

我尝试了所有的组合,比如

pattern: /some/path/\${app-name}.csv
pattern: "/some/path/\${app-name}.csv"
pattern: /some/path/#{'$'}{app-name}.csv
pattern: "/some/path/#{'$'}{app-name}.csv"

它们都不会生成包含请求字符串的变量,带有美元符号,但没有转义字符

请注意,它是YAML配置。在YAML文件中,#是行注释字符,从这个字符开始的所有内容都被忽略。如果我使用\#,那么\将被传递给字符串

补充:自2008年6月25日起,有一个Spring project open issue 9628开放:

There is presently no way to inject a ${...} expression that won't be picked up by PropertyPlaceholderConfigurer. Ideally we should be able to inject a string that contains ${...} for later use in its target bean without involvement from PropertyPlaceholderConfigurer.


共 (6) 个答案

  1. # 1 楼答案

    答案实际上取决于您将值注入代码的方式。由于您还没有提供,我将列出各种工作技巧

    1. 可以使用@Value注释来注入属性。因为unlike ^{}, ^{} does SpEL evaluation,你必须逃避你的价值

    申请。yml:

    csv:
      file:
        pattern: /some/path/#{'$'}{app-name}.csv
    

    测试控制器。爪哇:

    @RestController
    public class TestController {
        @Value("${csv.file.pattern}") private String pattern;
        @GetMapping("pattern") public ResponseEntity<String> getPattern() {
            return ResponseEntity.ok(pattern);
        }
    }
    

    进入/pattern会产生一个输出/some/path/#{app-name}.csv,正如您所需要的那样

    1. 您可以使用@ConfigurationProperties,这实际上取决于配置对象的结构。不过,一般来说,@ConfigurationProperties应该不需要转义,因为默认情况下它们不支持SpEL。不过,以下方法可以工作,因此如果您的设置不同,请修改它:

    申请。yml:

    csv:
      file:
        pattern: /some/path/#{app-name}.csv
    

    配置。爪哇:

    @ConfigurationProperties(prefix = "csv.file")
    public class Config {
        private String pattern;
        public String getPattern() { return pattern; }
        public void setPattern(String pattern) { this.pattern = pattern; }
    }
    

    测试控制器。爪哇:

    @RestController
    public class TestController {
        @Autowired private Config config;
        @GetMapping("pattern") public ResponseEntity<String> getPattern() {
            return ResponseEntity.ok(config.getPattern());
        }
    }
    

    同样,到达/pattern将导致输出/some/path/#{app-name}.csv

    你的配置中很可能有一些不同的结构。java(可能会发布相关代码?),这可能会导致无法正确处理该属性

  2. # 2 楼答案

    为什么不尝试使用${sys:$}这是丑陋但有效的。我想没有人会用$作为钥匙

  3. # 3 楼答案

    我也遇到了同样的问题。因此,您可以通过使用yaml文字样式符号“|”,或使用文字带“|-”,如下面的示例所示,来解决这个问题

    应用程序。yml

    csv:
      file:
        pattern: |-
          /some/path/${app-name}.csv
    

    实际上,我的问题是在yml中配置一个公式,然后在java中动态解析表达式。在这里分享解决方案

    我选择spring el解决方案并使用spring版本5.0.9.RELEASE

    我用yml定义了一个公式

    score:
      formula: |-
        10 * #x + #y
    

    然后在spring组件bean中

    @Value("${score.formula}")
    String scoreFormula;
    

    最后利用弹簧el

    ExpressionParser parser = new SpelExpressionParser();
    EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
    
    context.setVariable("x", 1);
    context.setVariable("y", 1);
    Integer score = parser.parseExpression(scoreFormula).getValue(context,Integer.class);
    

    参考

    yaml-multi-line

  4. # 4 楼答案

    我也有同样的问题,我只是找到了聪明的解决办法 定义一个名为dollarSign或ds的属性

    ds: "$"
    

    然后像这样使用它,在运行时${ds}将被$替换

    csv:
      file:
        pattern: /some/path/${ds}{app-name}.csv
    

    它起作用的时候有点好笑

  5. # 5 楼答案

    事实上,没有一个答案对我有用。然而,添加一个双美元符号对我来说很好:

    csv:
      file:
        pattern: /some/path/$${app-name}.csv
    
  6. # 6 楼答案

    Spring目前没有为属性占位符提供转义机制,有一个open issue(于2008年6月25日开放)。在评论中提到了这种变通方法(我不确定它是否适用于YAML):

    csv:
      file:
        pattern: /some/path/#{'$'}{app-name}.csv
    

    请注意,当在空格后或行首使用时,YAML中的#会开始一条注释