1.外部化配置
Spring Boot允許您外部化配置,以便您可以在不同的環境中使用相同的應用程序代碼。
您可以使用屬性文件,YAML文件,環境變量和命令行參數來外部化配置。
屬性值可以通過@Value注解直接注射到你的bean中,通過Spring的Environment,或者通過@ConfigurationProperties。
Spring Boot使用一種非常特殊的PropertySource順序,旨在允許合理地覆蓋值。按以下順序考慮屬性(優先級從高到低):
- Devtools 主目錄上的全局設置屬性(
~/.spring-boot-devtools.properties當devtools處於活動狀態時)。 @TestPropertySource測試代碼的屬性源注釋。測試代碼上的properties屬性- 命令行參數。
- 來自
SPRING_APPLICATION_JSON的屬性。 ServletConfiginit參數。ServletContextinit參數。- 來自
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-addressacme.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
要使用@ConfigurationPropertiesbean,可以使用與任何其他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
