Spring 的@Value 注解可用于将值注入 Spring 管理的 bean 的属性中,可以应用于属性或构造函数/方法参数级别。 属性注入使用
我们可以仅从注解中将“字符串值”注入到属性中:
@Value("字符串值") private String stringValue;
在以下示例中,我们将从文件中获取的值赋给字段:
@Value("{value.from.file}") private String valueFromFile;
我们还可以使用相同的语法从系统属性中设置值。 假设我们定义了一个名为 systemValue 的系统属性:
@Value("{systemValue}") private String systemValue;
可以为可能未定义的属性提供默认值。这里,值 some default 将被注入:
@Value("{unknown.param:some default}") private String someDefault;
如果同一个属性既定义为系统属性又在属性文件中定义,则将应用系统属性。 有时,我们需要注入一组值。将它们定义为属性文件或系统属性中的逗号分隔值并注入到数组中会很方便。 我们在属性文件的 listOfValues 中定义了逗号分隔值,注入方式:
@Value("{listOfValues}") private String[]valuesArray;
使用 SpEL 的高级示例
我们还可以使用 SpEL 表达式来获取值。 如果我们有一个名为 priority 的系统属性,则其值将被赋给字段:
@Value("#{systemProperties['priority']}") private String spelValue;
如果我们未定义系统属性,则将分配 null 值。 为了防止这种情况,我们可以在 SpEL 表达式中提供默认值。如果未定义系统属性,我们将为字段获得 some default 值:
@Value("#{systemProperties['unknown']?:'some default'}") private String spelSomeDefault;
此外,我们可以使用其他 bean 中的属性值。假设我们有一个名为 someBean 的 bean,其 someValue 等于 10。那么,10 将被赋给字段:
@Value("#{someBean.someValue}") private Integer someBeanValue;
我们可以操作属性以获得值列表,这里是一个包含字符串值 A、B 和 C 的列表:
@Value("#{'{listOfValues}'.split(',')}") private List valuesList;
使用@Value 注入 Maps
我们还可以使用@Value 注解来注入 Map 属性。 首先,我们需要在属性文件中以{key:‘value’}形式定义属性: valuesMap={key1:'1',key2:'2',key3:'3'} 注意,Map 中的值必须用单引号括起来。 现在我们可以从属性文件中将此值作为 Map 注入:
@Value("#{{valuesMap}}") private Map<String,Integer>valuesMap;
如果需要获取 Map 中特定键的值,只需在表达式中添加键的名称:
@Value("#{{valuesMap}.key1}") private Integer valuesMapKey1;
如果不确定 Map 是否包含某个键,应选择更安全的表达式,该表达式在找不到键时不会抛出异常,而是将值设置为 null:
@Value("#{{valuesMap}['unknownKey']}") private Integer unknownMapKey;
我们还可以为可能不存在的属性或键设置默认值:
@Value("#{{unknownMap:{key1:'1',key2:'2'}}}") private Map<String,Integer>unknownMap;
@Value("#{{valuesMap}['unknownKey']?:5}") private Integer unknownMapKeyWithDefaultValue;
在注入之前,还可以过滤 Map 条目。 假设我们需要获取值大于一的条目:
@Value("#{{valuesMap}.?[value>'1']}") private Map<String,Integer>valuesMapFiltered;
我们还可以使用@Value 注解来注入所有当前系统属性:
@Value("#{systemProperties}") private Map<String,String>systemPropertiesMap;
使用@Value 进行构造函数注入
当我们使用@Value 注解时,不仅限于属性注入。我们还可以将其与构造函数注入一起使用。 让我们在实践中看看:
@Autowired public PriorityProvider(@Value("${priority:normal}") String priority) { this.priority = priority; }
在上面的示例中,我们将 priority 直接注入到 PriorityProvider 的构造函数中。 注意,我们还提供了默认值,以防找不到该属性。 使用@Value 进行 Setter 注入
与构造函数注入类似,我们还可以使用@Value 进行 Setter 注入。 让我们看看:
private List<String> values = new ArrayList<>(); @Autowired public void setValues(@Value("#{'${listOfValues}'.split(',')}") List<String> values) { this.values.addAll(values); }
我们使用 SpEL 表达式将值列表注入到 setValues 方法中。
注:可以用方法注入,赋值给静态属性。 使用@Value 注解 Records
Java 14 引入了 records,以方便创建不可变类。Spring 框架从 6.0.6 版本开始支持@Value 进行 record 注入。
@Component @PropertySource("classpath:values.properties") public record PriorityRecord(@Value("{priority:normal}")String priority){} 在这里,我们将值直接注入到 record 的构造函数中。