1. 概述
在本快速教程中,我們將查看 Spring 註解 @Value。
此註解可用於向 Spring 管理的 Bean 中的字段注入值,並且可應用於字段、構造函數或方法參數級別。
2. 設置應用程序
為了描述這種標註的不同使用方式,我們需要配置一個簡單的 Spring 應用程序配置類。
自然地,我們需要一個 屬性文件來定義我們想要使用 @Value 註解注入的值。因此,我們需要在配置類中定義一個 @PropertySource —— 與屬性文件名相關聯。
讓我們定義屬性文件:
value.from.file=Value got from the file
priority=high
listOfValues=A,B,C3. 使用示例
作為一種基本且幾乎沒有用的示例,我們只能將“字符串值”從標註注入到字段中:
@Value("string value")
private String stringValue;使用 @PropertySource 註解,允許我們使用帶有 @Value 註解的屬性文件中的值。
在下面的示例中,我們從文件中獲取 值 並將其分配給字段:
@Value("${value.from.file}")
private String valueFromFile;我們還可以通過設置系統屬性來指定值,使用相同的語法。
假設我們已經定義了一個名為 systemValue 的系統屬性:
@Value("${systemValue}")
private String systemValue;可以為可能未定義的屬性提供默認值。在此,值 some default 將被注入:
@Value("${unknown.param:some default}")
private String someDefault;如果相同的屬性既作為系統屬性定義,又在屬性文件中定義,則系統屬性將被應用。
假設我們有一個屬性 priority 定義為系統屬性,值為 System property,同時在屬性文件中定義為其他值。則該值將為 System property:
@Value("${priority}")
private String prioritySystemProperty;有時,我們需要注入大量值。將它們定義為單個屬性的逗號分隔值,或者作為系統屬性並注入到數組中,將非常方便。
在第一部分中,我們定義了 listOfValues 屬性文件中的逗號分隔值,因此數組的值將是 ["A", "B", "C"]:
@Value("${listOfValues}")
private String[] valuesArray;4. 藉助 SpEL 的高級示例
我們可以使用 SpEL 表達式獲取值。
如果系統屬性名為 priority,,則其值將被應用於字段:
@Value("#{systemProperties['priority']}")
private String spelValue;如果未定義系統屬性,則將分配空值。
為了防止這種情況發生,我們可以為 SpEL 表達式提供默認值。如果未定義系統屬性,則可以獲取一些默認值用於該字段:
@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<String> valuesList;5. 使用 @Value 與 Map
我們還可以使用 @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;6. 使用 @Value 與構造函數注入
當我們使用 @Value 註解時,並不侷限於字段注入。 我們也可以將其與構造函數注入結合使用。
讓我們通過一個例子來演示:
@Component
@PropertySource("classpath:values.properties")
public class PriorityProvider {
private String priority;
@Autowired
public PriorityProvider(@Value("${priority:normal}") String priority) {
this.priority = priority;
}
// standard getter
}在上述示例中,我們直接向我們的 PriorityProvider 的構造函數注入了 優先級。
請注意,我們還提供了一個默認值,以防屬性未找到。
7. 使用 @Value 與 Setter 注入
類似於構造注入,我們也可以使用 @Value 與 setter 注入。
讓我們來看一個例子:
@Component
@PropertySource("classpath:values.properties")
public class CollectionProvider {
private List<String> values = new ArrayList<>();
@Autowired
public void setValues(@Value("#{'${listOfValues}'.split(',')}") List<String> values) {
this.values.addAll(values);
}
// standard getter
}我們使用 SpEL 表達式將一個值列表注入到 setValues 方法中。
8. 使用 @Value 與記錄 (Records)
Java 14 引入了記錄 (Records) 以簡化不可變類的創建。 Spring 框架自 6.0.6 版本起支持 @Value 用於記錄注入:
@Component
@PropertySource("classpath:values.properties")
public record PriorityRecord(@Value("${priority:normal}") String priority) {}在這裏,我們直接將值注入到記錄的構造函數中。
9. 結論
在本文中,我們探討了使用 @Value 註解與簡單文件屬性、系統屬性以及使用 SpEL 表達式計算的屬性的各種可能性。