可以在Spring的@Value注释中指定多个属性名称吗?

时间:2018-04-04 14:09:39

标签: java spring spring-boot properties

我已经熟悉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答案以及如何实现它...所以我想知道它是否可能,或者它是否&# 39;不是,是否有@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(:)'

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

3 个答案:

答案 0 :(得分:6)

您可以使用以下@Value注释:

@Configuration
public class MyConfig {

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

@Value注释使用com.mycompany.propertygroup.propertyname(如果已提供),如果未提供oldconvention.property,则默认为com.mycompany.propertygroup.propertyname。如果未提供,则属性设置为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;
       }
    }
}

答案 1 :(得分:2)

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

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

答案 2 :(得分:-3)

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

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

@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;