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