1.外部化配置
Spring Boot允許您外部化配置,以便您可以在不同的環境中使用相同的應用程序代碼。
您可以使用屬性文件,YAML文件,環境變量和命令行參數來外部化配置。
屬性值可以通過@Value注解直接注射到你的bean中,通過Spring的Environment
,或者通過@ConfigurationProperties
。
Spring Boot使用一種非常特殊的PropertySource
順序,旨在允許合理地覆蓋值。按以下順序考慮屬性(優先級從高到低):
- Devtools 主目錄上的全局設置屬性(
~/.spring-boot-devtools.properties
當devtools處於活動狀態時)。 @TestPropertySource
測試代碼的屬性源注釋。測試代碼上的properties
屬性- 命令行參數。
- 來自
SPRING_APPLICATION_JSON
的屬性。 ServletConfig
init參數。ServletContext
init參數。- 來自
java:comp/env的
JNDI屬性。 - Java系統屬性(
System.getProperties()
)。 - OS環境變量。
RandomValuePropertySource
,只有在擁有random.*屬性
。- jar包外面的特定於配置文件的應用程序屬性(
application-{profile}.properties
和YAML變體)。 - 打包在jar中的特定於配置文件的應用程序屬性(
application-{profile}.properties
以及YAML變體)。 - jar包之外的應用程序屬性(
application.properties
以及YAML變體)。 - jar包中的應用程序屬性(
application.properties
和YAML變體)。 @PropertySource
在@Configuration
類上的注釋。- 默認屬性(由設置指定
SpringApplication.setDefaultProperties
)。
要提供一個具體示例,假設您開發了一個@Component
使用name
屬性的示例,如以下示例所示:
import org.springframework.stereotype.*; import org.springframework.beans.factory.annotation.*; @Component public class MyBean { @Value("${name}") private String name; // ... }
在應用程序類路徑上(例如,在jar中),您可以擁有一個application.properties
為其提供合理的默認屬性值的文件name
。
在新環境中運行時,application.properties
可以在jar外部提供一個覆蓋該文件的文件name
。
對於一次性測試,您可以使用特定的命令行開關啟動(例如,java -jar app.jar --name="Spring"
)。
1.1配置文件加載優先級總結
默認的配置文件名為application.properties 或者 application.yml
配置屬性可以通過配置文件或者其他方式提供。它們的優先級大致如下:
命令行 > 系統屬性 > 環境變量 > 外部配置文件 > 內部配置文件
RandomValuePropertySource
對於注入隨機值很有用(例如,注入秘密或測試用例)。它可以生成整數,長整數,uuids或字符串,如以下示例所示:
my.secret=${random.value} my.number=${random.int} my.bignumber=${random.long} my.uuid=${random.uuid} my.number.less.than.ten=${random.int(10)} my.number.in.range=${random.int[1024,65536]}
默認情況下,SpringApplication
將任何命令行選項參數(即,以--開頭的參數,如
--server.port=9000
)轉化為property
,並將它們添加到spring Environment
。如前所述,命令行屬性始終優先於其他屬性源。
如果您不希望將命令行屬性添加到Environment
,則可以使用禁用它們SpringApplication.setAddCommandLineProperties(false)
。
SpringApplication
從application.properties
以下位置的文件加載屬性並將它們添加到Spring Environment
:
- 當前目錄的子目錄/config
- 當前目錄
- classpath 下的
/config
- classpath根路徑 /
上述列表按優先級排序(在列表中較高位置定義的屬性將覆蓋在較低位置中定義的屬性)。
如果您不喜歡application.properties
配置文件名,可以通過指定spring.config.name
環境屬性切換到另一個文件名。
您還可以使用spring.config.location環境
屬性(以逗號分隔的目錄位置或文件路徑列表)來顯示指定屬性文件位置。以下示例顯示指定其他文件名作為屬性文件:
java -jar myproject.jar --spring.config.name=myproject
以下示例顯示如何指定兩個位置:
$ java -jar myproject.jar --spring.config.location = classpath:/default.properties,classpath:/override.properties
如果spring.config.location
包含目錄(而不是文件),它們應該以/
(並且在運行時,附加spring.config.name
在加載之前生成的名稱,包括特定於配置文件的文件名)結束。
搜索以配置位置相反的順序。默認情況下,配置的位置是 classpath:/,classpath:/config/,file:./,file:./config/
。生成的搜索順序如下:
file:./config/
file:./
classpath:/config/
classpath:/
使用時配置自定義配置位置時spring.config.location
,它們會替換默認位置。例如,如果spring.config.location
配置了值classpath:/custom-config/,file:./custom-config/
,則搜索順序將變為:
file:./custom-config/
classpath:custom-config/
或者,當使用配置自定義配置位置時spring.config.additional-location
,除了配置路徑外,還會使用默認位置。在默認位置之前搜索其他位置。例如,如果classpath:/custom-config/,file:./custom-config/
配置了其他位置,則搜索順序將變為以下內容:
file:./custom-config/
classpath:custom-config/
file:./config/
file:./
classpath:/config/
classpath:/
此搜索順序允許您在一個配置文件中指定默認值,然后有選擇地覆蓋另一個配置文件中的值。您可以在其中一個默認位置為您的應用程序提供默認值application.properties
(或您選擇的任何其他名稱 spring.config.name
)。
然后,可以在運行時使用位於其中一個自定義位置的不同文件覆蓋這些默認值。
除application.properties
文件外,還可以使用以下命名約定來定義特定於配置文件的屬性:application-{profile}.properties
。
在 Environment
具有一組默認的配置文件(默認[default]
)如果沒有設置激活的profile(spring.profiles.active)。換句話說,如果沒有顯式激活配置文件,則從application-default.properties
加載屬性。
特定於配置文件的屬性從標准的相同位置加載 application.properties
,特定於配置文件的文件始終覆蓋非特定文件,無論特定於配置文件的文件是在打包的jar內部還是外部。
使用時,application.properties的值
將通過現有Environment值進行過濾 ,因此您可以使用先前定義的值(例如,使用“系統”屬性)。
app.name=MyApp
app.description=${app.name} is a Spring Boot application
YAML是JSON的超集。
Spring Framework提供了兩個方便的類,可用於加載YAML文檔。YamlPropertiesFactoryBean
加載YAML作為Properties,
YamlMapFactoryBean
加載YAML作為Map
。
例如,請考慮以下YAML文檔:
environments: dev: url: http://dev.example.com name: Developer Setup prod: url: http://another.example.com name: My Cool App
前面的示例將轉換為以下屬性:
environments.dev.url=http://dev.example.com environments.dev.name=Developer Setup environments.prod.url=http://another.example.com environments.prod.name=My Cool App
YAML列表表示為具有[index]
解除引用的屬性鍵。例如,考慮以下YAML:
my: servers: - dev.example.com - another.example.com
前面的示例將轉換為這些屬性:
my.servers[0]=dev.example.com
my.servers[1]=another.example.com
要通過使用Spring Boot的Binder
實用程序(類似 @ConfigurationProperties
)綁定到這樣的屬性,您需要在目標bean中具有屬性類型java.util.List
(或Set
), 並且您需要提供setter或使用可變值初始化它。例如,以下示例綁定到前面顯示的屬性:
@ConfigurationProperties(prefix="my") public class Config { private List<String> servers = new ArrayList<String>(); public List<String> getServers() { return this.servers; } }
YamlPropertySourceLoader
類可用於暴露YAML作為PropertySource
在spring Environment
。這樣做允許您使用@Value
帶占位符語法的注釋來訪問YAML屬性。需要額外配置。
您可以使用spring.profiles
鍵指定文檔何時適用,在單個文件中指定多個特定於配置文件的YAML文檔 ,如以下示例所示:
server: address: 192.168.1.100 --- spring: profiles: development server: address: 127.0.0.1 --- spring: profiles: production & eu-central server: address: 192.168.1.120
在前面的示例中,如果development
配置文件處於活動狀態,則server.address
屬性為127.0.0.1
。
同樣,如果production
和 eu-central
配置文件處於活動狀態,則server.address
屬性為192.168.1.120
。
如果development
, production
並eu-central
在配置文件沒有啟用,那么該屬性的值192.168.1.100
。
spring.security.user.password
可用:
server: port: 8000 --- spring: profiles: default security: user: password: weak
然而,在以下示例中,始終設置密碼,因為它未附加到任何配置文件,並且可以根據需要在所有其他配置文件中顯式重置密碼:
server: port: 8000 spring: security: user: password: weak
通過使用spring.profiles
元素指定激活的profile。
使用@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("acme") public class AcmeProperties { 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定義了以下屬性:
acme.enabled
,默認值為false。acme.remote-address
acme.security.username
,使用嵌套的“安全”對象,其名稱由屬性名稱決定。特別是,那里根本沒有使用返回類型SecurityProperties
。acme.security.password
。acme.security.roles
,String集合
。
(getter和setter通常是必需的,因為綁定是通過標准的Java Beans屬性描述符,就像在Spring MVC中一樣。)
您還需要列出要在@EnableConfigurationProperties
注釋中注冊的屬性類 ,如以下示例所示:
@Configuration @EnableConfigurationProperties(AcmeProperties.class) public class MyConfiguration { }
即使前面的配置創建了常規bean AcmeProperties
,我們也建議@ConfigurationProperties
只處理環境,特別是不從上下文中注入其他bean。
話雖如此,@EnableConfigurationProperties
注釋也會自動應用於您的項目,以便從中配置任何注釋的現有 bean 。
您可以通過確保 已經是bean 來快捷方式,如以下示例所示:
@Component @ConfigurationProperties(prefix="acme") public class AcmeProperties { // ... see the preceding example }
這種配置風格特別適用於SpringApplication
外部YAML配置,如以下示例所示:
# application.yml acme: remote-address: 192.168.1.1 security: username: admin roles: - USER - ADMIN # additional configuration as required
要使用@ConfigurationProperties
bean,可以使用與任何其他bean相同的方式注入它們,如以下示例所示:
@Service public class MyService { private final AcmeProperties properties; @Autowired public MyService(AcmeProperties properties) { this.properties = properties; } //... @PostConstruct public void openConnection() { Server server = new Server(this.properties.getRemoteAddress()); // ... } }
1.9 總結
屬性文件配置大致如上所述。
重點1:屬性配置文件的加載優先級,如何覆蓋
重點2:如何通過profile靈活切換不同的配置
重點3:如果將配置文件中的屬性自動注入到bean中
1.10 使用代碼設置(新增)
System.setProperty("spring.profiles.active", "local");
或者
SpringApplication application = new SpringApplication(MyApplication.class);
application.setAdditionalProfiles("dev","animal_dev");
application.run(args);
備注:
增加參考文檔 https://www.concretepage.com/spring-boot/spring-boot-profiles-example