1. 概述

本文将带你掌握如何从 Spring 的属性文件(如 application.properties)中,将配置值注入到数组或 List 类型的字段中。这在实际开发中非常常见,比如配置白名单、启用的模块列表等。掌握这些技巧能让你的配置更灵活,少踩坑。

2. 数组的默认注入行为

我们从一个简单的 application.properties 开始:

arrayOfStrings=Baeldung,dot,com

使用 @Value 注解直接注入到 String[] 类型:

@Value("${arrayOfStrings}")
private String[] arrayOfStrings;

测试验证结果:

@Test
void whenContextIsInitialized_thenInjectedArrayContainsExpectedValues() {
    assertArrayEquals(new String[] {"Baeldung", "dot", "com"}, arrayOfStrings);
}

结论:Spring 默认会将逗号(,)作为分隔符,自动将字符串拆分为数组元素。

⚠️ 注意:这种“开箱即用”的数组注入仅支持逗号分隔。如果你用分号或其它符号,会直接报错或行为异常。

3. List 的注入:SpEL 是关键

如果你尝试用同样的方式注入 List<String>

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

结果会让你大跌眼镜:

@Test
void whenContextIsInitialized_thenInjectedListContainsUnexpectedValues() {
    assertEquals(Collections.singletonList("Baeldung,dot,com"), unexpectedListOfStrings);
}

问题List 中只有一个元素,就是原始字符串 "Baeldung,dot,com",并没有被拆分。

✅ 正确姿势:使用 SpEL 表达式

必须借助 Spring 表达式语言(SpEL)手动拆分:

@Value("#{'${arrayOfStrings}'.split(',')}")
private List<String> listOfStrings;

测试通过:

@Test
void whenContextIsInitialized_thenInjectedListContainsExpectedValues() {
    assertEquals(Arrays.asList("Baeldung", "dot", "com"), listOfStrings);
}

📌 解析:

  • # 表示这是 SpEL 表达式
  • ${arrayOfStrings} 从 properties 中取值
  • .split(',') 将字符串按逗号拆分为 String[]
  • Spring 自动将数组转为 List

🛠 更简洁的写法:使用花括号格式

你也可以在配置文件中直接使用 SpEL 兼容格式:

listOfStrings={'Baeldung','dot','com'}

然后注入时只需:

@Value("#{${listOfStrings}}")
private List<String> listOfStringsV2;

这种方式更清晰,避免了 .split() 的字符串操作,适合固定值配置。

4. 使用自定义分隔符

实际项目中,配置可能用分号 ; 或竖线 | 分隔。比如:

listOfStringsWithCustomDelimiter=Baeldung;dot;com

此时只需在 SpEL 中指定分隔符即可:

@Value("#{'${listOfStringsWithCustomDelimiter}'.split(';')}")
private List<String> listOfStringsWithCustomDelimiter;

测试验证:

@Test
void whenContextIsInitialized_thenInjectedListWithCustomDelimiterContainsExpectedValues() {
    assertEquals(Arrays.asList("Baeldung", "dot", "com"), listOfStringsWithCustomDelimiter);
}

✅ 灵活可控,简单粗暴。

5. 注入其他基本类型集合

Spring 对基本类型(Boolean, Integer, Character 等)的集合注入也支持良好,前提是使用 SpEL:

listOfBooleans=false,false,true
listOfIntegers=1,2,3,4
listOfCharacters=a,b,c

注入代码:

@Value("#{'${listOfBooleans}'.split(',')}")
private List<Boolean> listOfBooleans;

@Value("#{'${listOfIntegers}'.split(',')}")
private List<Integer> listOfIntegers;

@Value("#{'${listOfCharacters}'.split(',')}")
private List<Character> listOfCharacters;

测试:

@Test
void whenContextIsInitialized_thenInjectedListOfBasicTypesContainsExpectedValues() {
    assertEquals(Arrays.asList(false, false, true), listOfBooleans);
    assertEquals(Arrays.asList(1, 2, 3, 4), listOfIntegers);
    assertEquals(Arrays.asList('a', 'b', 'c'), listOfCharacters);
}

📌 注意:这些类型无法通过 @Value("${prop}") 直接注入数组,必须走 SpEL 路径。

6. 编程式读取配置

有时候你不想用注解,或者需要动态获取配置。可以通过 Environment 接口实现:

@Autowired
private Environment environment;

然后直接读取并转换类型:

@Test
void whenReadingFromSpringEnvironment_thenPropertiesHaveExpectedValues() {
    String[] arrayOfStrings = environment.getProperty("arrayOfStrings", String[].class);
    List<String> listOfStrings = environment.getProperty("arrayOfStrings", List.class);

    assertArrayEquals(new String[] {"Baeldung", "dot", "com"}, arrayOfStrings);
    assertEquals(Arrays.asList("Baeldung", "dot", "com"), listOfStrings);
}

✅ 优势:

  • 类型安全
  • 支持 List 和数组自动转换
  • 可在任意 Bean 中使用,不依赖字段注入

7. 总结

场景 推荐方式
注入 String[](逗号分隔) @Value("${prop}")
注入 List<T> @Value("#{'${prop}'.split(','))")
自定义分隔符 .split('分隔符')
固定值列表 配置写成 {'a','b'},注入 #{${prop}}
编程式读取 environment.getProperty(key, targetType)

记住一个核心:List 注入绕不开 SpEL。理解这一点,配置注入就再也没坑了。

示例代码已上传至 GitHub:https://github.com/baeldung/spring-boot-tutorials/tree/master/spring-boot-properties-2


原始标题:Inject Arrays & Lists from Spring Property Files | Baeldung