从属性文件中读取列表,并使用Spring注解@Value加载

322

我希望在一个 .properties 文件中有一个值列表,即:

my.list.of.strings=ABC,CDE,EFG

直接在我的类中加载它,即:
@Value("${my.list.of.strings}")
private List<String> myList;

根据我的理解,另一种方法是将其放在Spring的配置文件中,并作为一个bean引用加载(如果我理解错误,请纠正),即:
<bean name="list">
 <list>
  <value>ABC</value>
  <value>CDE</value>
  <value>EFG</value>
 </list>
</bean>

但是有没有办法使用.properties文件来实现这个呢?
附言:
如果可能的话,我希望不使用任何自定义代码来完成这个任务。

如何使用@value读取List<int[]>范围 - Nikhil Kulkarni
17个回答

596

使用Spring EL:

@Value("#{'${my.list.of.strings}'.split(',')}") 
private List<String> myList;

假设你的属性文件已经正确加载,包括以下内容:

my.list.of.strings=ABC,CDE,EFG

1
与Spring 3.2完美兼容。 - ehsanullahjan
25
空属性 my.list.of.strings= 怎么样?我期望这个功能会返回一个空列表,但实际上它会返回一个包含一个空字符串的列表。你对此有何看法? - Jan Zyka
1
我创建了自定义静态方法来实现这个功能。首先检查输入的字符串是否为空,如果是,则返回空列表。否则进行分割。您可以轻松地在EL中调用静态方法。 - Jan Zyka
5
请注意,建议的解决方案不进行修剪操作,因此具有空格的值(例如 item1,item2,item3)可能会产生您并不真正预期的结果(提示:空格)。 - Jan Zyka
12
如果您需要修剪空格,请使用正则表达式作为分隔符参数。例如:@Value("#{'${my.list.of.strings}'.split(',\\s*')}") - Stackee007
显示剩余10条评论

112

自从Spring 3.0以来,您可以添加如下一行代码:

<bean id="conversionService" 
    class="org.springframework.context.support.ConversionServiceFactoryBean" />

将内容配置到您的applicationContext.xml文件(或您配置内容的位置)中。 正如Dmitry Chornyi在评论中指出的,基于Java的配置如下:

@Bean public ConversionService conversionService() {
    return new DefaultConversionService();
}

这将激活新的配置服务,支持将 String 转换成 Collection 类型。如果您没有激活此配置服务,则 Spring 将退回到其旧版属性编辑器作为配置服务,这些编辑器不支持此类转换。

转换为其他类型的集合也可以使用:

@Value("${my.list.of.ints}")
private List<Integer> myList

将使用类似以下行的方式工作

 my.list.of.ints= 1, 2, 3, 4

对于空格没有任何问题,ConversionServiceFactoryBean 已经处理好了。

请参考http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#core-convert-Spring-config

在一个Spring应用程序中,通常会为每个Spring容器(或ApplicationContext)配置一个ConversionService实例。该ConversionService将被Spring捕获,然后在框架需要执行类型转换时使用。 [...] 如果没有为Spring注册ConversionService,则将使用原始基于PropertyEditor的系统。


8
Java配置:@Bean public ConversionService conversionService() { return new DefaultConversionService(); } - Dmitry Chornyi
2
除了避免在每个表达式中重复使用 split()之外,它还可以正确处理空列表,而不是给出 [null] - Didier L
如果属性被覆盖(存在于多个属性源中),则它将无法正常工作。 - Daniel Hári

60
如果你正在阅读这篇文章并且正在使用 Spring Boot,那么你现在有另一个选项可以使用此功能。
通常情况下,逗号分隔的列表在实际应用中非常笨重(如果您想在配置中使用逗号,有时甚至不可行)。
email.sendTo=somebody@example.com,somebody2@example.com,somebody3@example.com,.....

使用Spring Boot,你可以像这样编写代码(索引从0开始):

email.sendTo[0]=somebody@example.com
email.sendTo[1]=somebody2@example.com
email.sendTo[2]=somebody3@example.com

并像这样使用:

@Component
@ConfigurationProperties("email")
public class EmailProperties {

    private List<String> sendTo;

    public List<String> getSendTo() {
        return sendTo;
    }

    public void setSendTo(List<String> sendTo) {
        this.sendTo = sendTo;
    }

}


@Component
public class EmailModel {

  @Autowired
  private EmailProperties emailProperties;

  //Use the sendTo List by 
  //emailProperties.getSendTo()

}



@Configuration
public class YourConfiguration {
    @Bean
  public EmailProperties emailProperties(){
        return new EmailProperties();
  }

}


#Put this in src/main/resource/META-INF/spring.factories
  org.springframework.boot.autoconfigure.EnableAutoConfiguration=example.compackage.YourConfiguration

我有一个问题,其他在这里描述的解决方案由于逗号被转义而无法识别。是否有一种使用Spring 4实现此解决方案的方法? - sandrozbinden

55
如果您正在使用Spring Boot 2,它可以直接工作,无需任何额外配置。
my.list.of.strings=ABC,CDE,EFG

@Value("${my.list.of.strings}")
private List<String> myList;

1
对我来说不起作用,我必须使用如上所示的Spring EL。 - Bilbo Baggins
甚至是 private List<String> myList; - Halayem Anis
2
是的,它也对我起作用了:我正在使用Spring Boot 2.2.6。 - Ankit

47
通过在.properties文件中指定my.list.of.strings=ABC,CDE,EFG,并使用 @Value("${my.list.of.strings}") private String[] myString; 您可以获取字符串数组。使用CollectionUtils.addAll(myList, myString),您可以获得字符串列表。

我只得到了第一个字符串“ABC”。 - Osama Abdulsattar

20

你考虑过在构造函数或setter中使用@Autowired,然后在方法体中使用String.split()吗?

class MyClass {
    private List<String> myList;

    @Autowired
    public MyClass(@Value("${my.list.of.strings}") final String strs) {
        myList = Arrays.asList(strs.split(","));
    }

    //or

    @Autowired
    public void setMyList(@Value("${my.list.of.strings}") final String strs) {
        myList = Arrays.asList(strs.split(","));
    }
}

我倾向于通过以下方式之一来进行自动装配,以增强代码的可测试性。


13

如果你正在使用最新的Spring框架版本(我相信是Spring 3.1+),那么在SpringEL中不需要使用那些字符串分割的东西。

只需要在你的Spring配置类中(带有@Configuration注解的那个)添加PropertySourcesPlaceholderConfigurer和DefaultConversionService即可,例如:

@Configuration
public class AppConfiguration {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean public ConversionService conversionService() {
        return new DefaultConversionService();
    }
}

而且在你的班级里

@Value("${list}")
private List<String> list;

并且在属性文件中

list=A,B,C,D,E

如果没有DefaultConversionService,当你将值注入到字段中时,你只能将逗号分隔的字符串转换为字符串数组,但是DefaultConversionService会为您执行一些方便的操作,并将它们添加到集合、数组等中。(如果想了解更多信息,请检查其实现)

有了这两个,甚至可以处理包括换行符在内的所有冗余空格,因此您无需添加额外的逻辑来修剪它们。


添加此配置是有效的,但发生了一些奇怪的事情: 我无法使用@Value来处理文件类型,必须将File更改为Resource。 - ad3luc

10
所有上述答案都是正确的。但您可以只用一行代码实现此操作。请尝试以下声明,您将获得一个字符串列表中的所有逗号分隔值。
private @Value("#{T(java.util.Arrays).asList(projectProperties['my.list.of.strings'])}") List<String> myList;

另外,你还需要在XML配置中定义以下行。

<util:properties id="projectProperties" location="/project.properties"/>

只需替换您的属性文件路径和文件名,就可以开始使用了。:)

希望这可以帮助您。干杯。


2
这对我有用,但我必须像这样表达注释:@Value("#{T(java.util.Arrays).asList('${my.list.of.strings}')}") - Steven

9

我正在使用Spring Boot 2.2.6

我的属性文件:

usa.big.banks= JP Morgan, Wells Fargo, Citigroup, Morgan Stanley, Goldman Sachs

我的代码:

@Value("${usa.big.banks}")
    private List<String> bigBanks;

@RequestMapping("/bigbanks")
    public String getBanks() {
        System.out.println("bigBanks = " + bigBanks);
        return bigBanks.toString();
    }

它运行正常。


6

对于字符串来说,我更喜欢以下方式:

admin.user={'Doe, John','Headroom, Max','Mouse, Micky'}

并使用

@Value("#{${admin.user}}")
private List<String> userList;

以此方式,您可以在参数中包含逗号。这也适用于集合(Sets)。

Spring 是通过哪些底层代码进行转换的?这些代码位于何处? - Toofy
这是 SpELl 读取属性 admin.user('${admin.user}',请参见 https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions),然后解析其中的内容('#{....}' 语法,请参见 https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-value-annotations)。 - Sampisa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接