詳細介紹Spring boot的關鍵特徵,針對有一定springboot基礎的同學。
##目錄
- 1 外部配置
- 1.7 型別安全配置Properties
- 1.7.1 第三方配置
- 1.7.2 輕鬆繫結
- 1.7.3 屬性轉換
- 1.7.4 @ConfigurationProperties驗證
- 1.7.5 @ConfigurationProperties vs. @Value
- 1.7 型別安全配置Properties
1. 外部配置
1.7 型別安全配置Properties
使用@Value(“$ {property}”)註釋來注入配置屬性有時可能很麻煩,特別是如果您正在使用多個屬性或資料是層次結構的屬性。 Spring Boot提供了一種處理屬性的替代方法,它允許強型別bean來管理和驗證應用程式的配置。
package com.example;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("foo")
public class FooProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() { ... }
public void setEnabled(boolean enabled) { ... }
public InetAddress getRemoteAddress() { ... }
public void setRemoteAddress(InetAddress remoteAddress) { ... }
public Security getSecurity() { ... }
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() { ... }
public void setUsername(String username) { ... }
public String getPassword() { ... }
public void setPassword(String password) { ... }
public List<String> getRoles() { ... }
public void setRoles(List<String> roles) { ... }
}
}複製程式碼
上述POJO定義了以下屬性:
- foo.enabled,預設為false
- foo.remote-address,可以強轉為String
- foo.security.username強制的型別,其中巢狀的“安全性”的名稱由屬性名稱決定。特別是返回型別並沒有被使用,並且可以是SecurityProperties
- foo.security.password
- foo.security.roles,其中包含String
注意:
Getters和setter通常是強制性的,因為繫結是通過標準的Java Beans屬性描述符,就像在Spring MVC中一樣。在某些情況下可能會忽略一個設定器:
- 只要初始化它們就需要一個getter,但不一定是一個setter,因為它們可以被binder繫結。
- 集合和陣列可以通過索引(通常使用YAML)或使用單個逗號分隔值(屬性)來訪問。在後一種情況下,設定者是強制性的。我們建議您始終為此型別新增一個設定器。如果初始化集合,請確保它不是不可變的(如上例)
- 如果已初始化巢狀POJO屬性(如上例中的Security欄位),則不需要setter。如果您希望binder使用其預設建構函式即時建立例項,則需要一個setter。
有些人使用Project Lombok自動新增getter和setter。確保Lombok不會為此型別生成任何特定的建構函式因為它將被容器自動使用來例項化物件。
您還需要列出要在@EnableConfigurationProperties註釋中註冊的屬性類:
@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration {
}複製程式碼
注意:
當@ConfigurationProperties bean以這種方式註冊時,該bean將具有常規名稱:–,在@ConfigurationProperties註釋中指定的環境金鑰字首和bean的完全限定名稱。如果註釋不提供任何字首,則僅使用該bean的完全限定名稱。
上面示例中的bean名稱將是foo-com.example.FooProperties。
即使上述配置將為FooProperties建立一個常規bean,我們建議@ConfigurationProperties僅通過Environment處理,特別是不從上下文中注入其他bean。話雖如此,@EnableConfigurationProperties註釋也會自動應用於您的專案,以便使用@ConfigurationProperties註釋的所有現有bean都將從Environment配置。您可以通過確保FooProperties已經是一個bean來快速上面的MyConfiguration
@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {
// ... see above
}複製程式碼
這種配置方式與SpringApplication外部YAML配置相當:
# application.yml
foo:
remote-address: 192.168.1.1
security:
username: foo
roles:
- USER
- ADMIN
# additional configuration as required複製程式碼
要使用@ConfigurationProperties bean,您可以像其他任何bean一樣注入它們。
@Service
public class MyService {
private final FooProperties properties;
@Autowired
public MyService(FooProperties properties) {
this.properties = properties;
}
//...
@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}
}複製程式碼
使用@ConfigurationProperties還可以生成IDE可以為自己的金鑰提供自動完成的後設資料檔案。
1.7.1 第三方配置
除了使用@ConfigurationProperties來註釋類,還可以在public @Bean方法中使用它。當您希望將屬性繫結到不受控制的第三方元件時,這可能特別有用。
要從Environment屬性配置一個bean,請將@ConfigurationProperties新增到其Bean註冊中:
@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
...
}複製程式碼
使用bar字首定義的任何屬性將以與上述FooProperties示例類似的方式對映到該BarComponent bean上
1.7.2 輕鬆繫結
Spring Boot使用一些輕鬆的規則將Environment屬性繫結到@ConfigurationProperties bean,因此不需要在Environment屬性名稱和bean屬性名稱之間進行完全匹配。常用的例子是有用的,例如虛線分隔(例如上下文路徑繫結到contextPath)和大寫(例如PORT繫結到埠)環境屬性。例如,給定以下@ConfigurationProperties類:
@ConfigurationProperties(prefix="person")
public class OwnerProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}複製程式碼
可以使用以下屬性名稱:
屬性 | 注意 |
---|---|
person.firstName | 標準駝峰語法。 |
person.first-name | 虛擬符號,推薦用於.properties和.yml檔案。 |
person.first_name | 下劃線符號,用於.properties和.yml檔案的替代格式。 |
PERSON_FIRST_NAME | 大寫格式。推薦使用系統環境變數時。 |
1.7.3 屬性轉換
當Spring繫結到@ConfigurationProperties bean時,Spring將嘗試將外部應用程式屬性強制為正確的型別。如果需要自定義型別轉換,您可以提供ConversionService bean(使用bean id conversionService)或自定義屬性編輯器(通過CustomEditorConfigurer bean)或自定義轉換器(使用註釋為@ConfigurationPropertiesBinding的bean定義)。
注意:
由於在應用程式生命週期中早期請求了該bean,因此請確保限制ConversionService正在使用的依賴關係。通常,您需要的任何依賴項可能在建立時可能未完全初始化。如果配置金鑰強制不需要,並且僅依賴使用@ConfigurationPropertiesBinding限定的自定義轉換器,則可能需要重新命名自定義ConversionService。
1.7.4 @ConfigurationProperties驗證
Spring引導將嘗試使用Spring的@Validated註釋來註釋@ConfigurationProperties類。您可以直接在配置類上使用JSR-303 javax.validation約束註釋。只需確保您的類路徑中符合JSR-303的實現,然後在您的欄位中新增約束註釋:
@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}複製程式碼
為了驗證巢狀屬性的值,您必須將關聯欄位註釋為@Valid以觸發其驗證。例如,基於上述FooProperties示例:
@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// ... getters and setters
public static class Security {
@NotEmpty
public String username;
// ... getters and setters
}
}複製程式碼
您還可以通過建立名為configurationPropertiesValidator的bean定義來新增自定義的Spring Validator。 @Bean方法應該宣告為靜態的。配置屬性驗證器是在應用程式的生命週期早期建立的,並宣告@Bean方法,因為static允許建立bean,而無需例項化@Configuration類。這避免了早期例項化可能引起的任何問題。有一個屬性驗證樣本,所以你可以看到如何設定。
注意:
spring-boot-actuator模組包括一個暴露所有@ConfigurationProperties bean的端點。只需將您的Web瀏覽器指向/configprops或使用等效的JMX終結點。
1.7.5 @ConfigurationProperties vs. @Value
@Value是核心容器功能,它不提供與型別安全配置屬性相同的功能。下表總結了@ConfigurationProperties和@Value支援的功能:
Feature | @ConfigurationProperties | @Value |
---|---|---|
Relaxed binding | Yes | No |
Meta-data support | Yes | No |
SpEL evaluation | No | Yes |
如果您為自己的元件定義了一組配置金鑰,我們建議您可以將它們分組到使用@ConfigurationProperties註釋的POJO中。還請注意,由於@Value不支援輕鬆繫結,如果您需要使用環境變數提供該值,那麼它不是一個很好的候選人。最後,當您可以在@Value中編寫一個SpEL表示式時,這些表示式不會從應用程式屬性檔案處理。