【问题标题】:Can multiple property names be specified in Spring's @Value annotation?Spring的@Value注解中可以指定多个属性名吗?
【发布时间】:2018-09-14 03:32:17
【问题描述】:

我已经熟悉 Spring 的 @Value 注释的基本行为,可以将字段设置为项目属性的值,如下所示:

项目的属性文件

foo.bar=value

项目的配置类

@Configuration
public class MyConfig {
    @Value("${foo.bar}")
    private String myValue;
}

但是,我正在尝试使用条件配置制作 SpringBoot 入门项目,并希望将属性名称标准化为有用的名称,例如“com.mycompany.propertygroup.propertyname”,但为了简化过渡并鼓励采用,我想要暂时也支持旧的属性名称,因此想知道是否有某种方法可以允许多个属性名称设置相同的字段?例如:

我的理论入门配置

@Configuration
public class MyConfig {
    @Value("${com.mycompany.propertygroup.propertyname}" || "${oldconvention.property}")
    private String myValue;
}

项目 A 的属性

oldconvention.property=value

项目 B 的财产

com.mycompany.propertygroup.propertyname=value

我似乎找不到任何文档或 SO 答案,说明这是否可能以及如何实现它......所以我想知道它是否可能,或者如果不是,是否有替代@Value注解可以达到同样的效果吗?

编辑澄清: 我不想跟踪多个值,所以我不需要关于如何获取多个值的说明……目标是合并成一个可能有多个名称的 SINGLE VALUE。在实践中,每个使用启动器的项目只有一个名称-值......只有在极少数情况下,当有人可能忘记删除旧属性时,才会使用每个属性名称(无论如何它可能具有相同的值)。在这种情况下,新的公约名称值将是唯一使用的。

更新

虽然提供的 SpEL 表达式答案在两个属性都存在时有效,但当只有一个属性名称存在时,应用程序上下文无法加载。示例:

更新的配置类

@Value("#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}"
private String myProperty;

更新的属性文件

com.mycompany.propertygroup.propertyname=somevalue

错误

Caused by: java.lang.IllegalArgumentException: 
Could not resolve placeholder 'oldconvention.propertyname' in value
"#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}"

要求两个属性名称都存在违背了目的,即允许实施项目使用旧约定或新约定来配置此启动器...

另一个更新...

我一直在使用 SpEL 表达式,当属性存在和不存在时,条件检查都有效,但事后我遇到了属性解析问题。我认为问题在于属性默认值和复杂的 SpEL 表达式不能很好地结合在一起。

@Value("#{${com.mycompany.propertygroup.propertyname:null} != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}")
private String myProperty;

当我的 SpEL 像上面那样编写时,我得到一个无法解析属性占位符异常,这意味着必须存在两个属性才能使 SpEL 表达式进行评估。所以我开始思考,我可以使用我见过的用于解析可选属性的默认属性语法:@Value("${myoptionalproperty:defaultValue}")

所以下面是我尝试将默认属性解析与 SpEL 表达式结合起来:

@Value("#{${com.mycompany.propertygroup.propertyname:null} != null ? '${com.mycompany.propertygroup.propertyname:}' : '${oldconvention.propertyname:}'}")
private String myProperty;

使用默认属性表示法时,我不断收到此错误:

org.springframework.expression.spel.SpelParseException: 
EL1041E: After parsing a valid expression, there is still more data in the expression: 'colon(:)'

当我用谷歌搜索该错误时,流行的答案是属性必须用单引号括起来,以便它们评估为字符串......但它们已经被包装了(除了第一个......我不得不解包那是因为我希望将其评估为空值检查的文字空值)。所以我认为当它们被包装在一个拼写表达式中时,默认值不能与属性一起使用。事实上,我只在@Value 注释仅使用纯属性持有者设置时见过默认属性集,而我在 SpEL 表达式中看到的所有属性都没有默认集。

【问题讨论】:

  • 假设可以做到这一点,如果用户同时拥有旧约定和新约定会发生什么?
  • @pvpkiran ,在这种情况下,我会赞成新的约定而不是旧的约定。
  • 下面的方法你可以做到。数组值:[“A”, “B”, “C”] @Value("${listOfValues}") private String[] valuesArray;
  • baeldung.com/spring-value-annotation --> 参见 spring 文档
  • @Value("${com.mycompany.propertygroup.propertyname:${oldconvention.property}}") 应该可以解决问题。

标签: java spring spring-boot properties


【解决方案1】:

可以使用以下@Value注解:

@Configuration
public class MyConfig {

    @Value("#{'${com.mycompany.propertygroup.propertyname:${oldconvention.propertyname:}}'}")
    private String myValue;
}

如果提供了@Value 注释,则使用com.mycompany.propertygroup.propertyname,如果未提供com.mycompany.propertygroup.propertyname,则默认为oldconvention.property。如果两者均未提供,则该属性设置为 null。您可以将此默认值设置为另一个值,方法是将 null 替换为另一个所需值。

有关详细信息,请参阅以下内容:


作为替代方案,您可以捕获两个值并在返回值之前进行选择:

@Configuration
public class MyConfig {

    @Value("${com.mycompany.propertygroup.propertyname:}")
    private String newValue;

    @Value("${oldconvention.propertyname:}")
    private String oldValue;

    public String getValue() {

        if (newValue != null && !newValue.isEmpty()) {
            // New value is provided
            System.out.println("New Value: " + newValue);
            return newValue;
        }
        else {
            // Default to the old value
            return oldValue;
       }
    }
}

【讨论】:

  • @AEvans 明白了。两者都可以(我的意见不一定适用于您的情况)。对于boolean 值,我认为您对虚假评估是正确的。为避免这种情况,您可以将值设置为Boolean,然后检查它是否为null@Value("#{com.mycompany.propertygroup.propertyname != null ? com.mycompany.propertygroup.propertyname : oldconvention.property}")。有关详细信息,请参阅 docs.spring.io/spring/docs/current/spring-framework-reference/…baeldung.com/spring-value-defaults 的 Primitives 部分
  • @JustinAlbano 感谢您提供文档链接;他们帮了大忙!但是在实践中,条件 SpEL 似乎仅在定义了两个属性时才有效,而不是允许项目仅指定属性之一,上下文将无法加载,因为 SpEL 错误无法执行其中一个属性替换...
  • @AEvans 尝试:@Value("#{'${com.mycompany.propertygroup.propertyname:${oldconvention.propertyname:null}}'}")。我已经用一个模拟应用程序对其进行了测试,如果它存在,它能够获得com.mycompany.propertygroup.propertyname 的值;如果不是,则使用oldconvention.propertyname 的值;如果两者都不存在,则返回 null。让我知道它是否适用于您的应用程序。
  • 我的最终解决方案:/* Use the fully qualified name of the property if available, otherwise, * look for the old name convention for backwards compatibility. Defaults * to null if neither property is found. */ @Value("#{'${com.mycompany.propertygroup.propertyname:${oldconvention.propertyname:}}'}") private String myValue;
  • @AEvans 有道理。我已经更新了使用空默认值的解决方案。
【解决方案2】:

不,我相信这是不可能的,但是是的,您可以将属性定义为逗号分隔。例如 com.mycompany.propertygroup.propertyname=value1,value2,value3

您可以像这样在String[] 上注释@Value 而不是接收字符串:

@Value("#{'${com.mycompany.propertygroup.propertyname}'.split(',')}")
private String[] propertyNames;

另一种方式,您也可以将键和值作为逗号分隔的字符串存储在属性文件中,并使用@Value 注释可以映射到Map,例如,您希望组名作为键,值作为组详细信息所以在属性文件中你可以像这样存储字符串

group.details.property= {'group1':'group1.details','group2':'group2.details'}

你可以将@Value注释为

@Value("#{${group.details.property}}")
private Map<String, String> groupMap;

【讨论】:

  • 目的不是检索多个属性值,而是将多个属性名称解析为一个值。
  • 或者也许真的不可能......我认为接受的答案有效,但我最初只测试了这两个属性。一旦缺少其中一个属性,SpEL 就无法评估。我不接受使用 SpEL 的答案,并用这些新发现更新了问题。
【解决方案3】:

使用 SPEL 是解决此问题的最佳方法。这应该工作

@Value("#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.property}'}")
private String myValue;

【讨论】:

  • 所以起初我认为这是成功的,因为它似乎有效......但我只测试了旧约定和新约定属性都存在时......一旦其中一个不存在t 指定时,SPEL 无法对缺少的任何属性进行评估,并出现“无法解析属性占位符”错误。
猜你喜欢
  • 1970-01-01
  • 2011-09-19
  • 2014-08-27
  • 2011-10-31
  • 2013-01-15
  • 2012-01-01
  • 1970-01-01
  • 2017-01-20
  • 2022-06-22
相关资源
最近更新 更多