一.簡述
Spring Boot 默認支持 properties(.properties) 和 YAML(.yml .yaml ) 兩種格式的配置文件,yml 和 properties 文件都屬於配置文件,功能一樣。
Spring Cloud 構建於 Spring Boot 之上,在 Spring Boot 中有兩種上下文,一種是 bootstrap,另外一種是 application,下面列舉這兩種配置文件的區別
1.加載順序
若application.yml 和bootstrap.yml 在同一目錄下:bootstrap.yml 先加載 application.yml后加載
bootstrap.yml 用於應用程序上下文的引導階段。bootstrap.yml 由父Spring ApplicationContext加載。
2.配置區別
bootstrap.yml 和 application.yml 都可以用來配置參數。
bootstrap.yml 用來程序引導時執行,應用於更加早期配置信息讀取。可以理解成系統級別的一些參數配置,這些參數一般是不會變動的。一旦bootStrap.yml 被加載,則內容不會被覆蓋。
application.yml 可以用來定義應用級別的, 應用程序特有配置信息,可以用來配置后續各個模塊中需使用的公共參數等。
3.屬性覆蓋問題
啟動上下文時,Spring Cloud 會創建一個 Bootstrap Context,作為 Spring 應用的 Application Context 的父上下文。
初始化的時候,Bootstrap Context 負責從外部源加載配置屬性並解析配置。這兩個上下文共享一個從外部獲取的 Environment。Bootstrap 屬性有高優先級,默認情況下,它們不會被本地配置覆蓋。
也就是說如果加載的 application.yml 的內容標簽與 bootstrap 的標簽一致,application 也不會覆蓋 bootstrap,而 application.yml 里面的內容可以動態替換。
二、典型的應用場景如下:
- 當使用 Spring Cloud Config Server 的時候,你應該在 bootstrap.yml 里面指定 spring.application.name 和 spring.cloud.config.server.git.uri
- 和一些加密/解密的信息
技術上,bootstrap.yml 是被一個父級的 Spring ApplicationContext 加載的。這個父級的 Spring ApplicationContext是先加載的,在加載application.yml 的 ApplicationContext之前。
為何需要把 config server 的信息放在 bootstrap.yml 里?
當使用 Spring Cloud 的時候,配置信息一般是從 config server 加載的,為了取得配置信息(比如密碼等),你需要一些提早的或引導配置。因此,把 config server 信息放在 bootstrap.yml,用來加載真正需要的配置信息。
三、高級使用場景
啟動上下文
Spring Cloud會創建一個Bootstrap Context
,作為Spring應用的Application Context
的父上下文。初始化的時候,Bootstrap Context
負責從外部源加載配置屬性並解析配置。這兩個上下文共享一個從外部獲取的Environment
。Bootstrap
屬性有高優先級,默認情況下,它們不會被本地配置覆蓋。 Bootstrap context
和Application Context
有着不同的約定,所以新增了一個bootstrap.yml
文件,而不是使用application.yml
(或者application.properties
)。保證Bootstrap Context
和Application Context
配置的分離。
下面是一個例子: bootstrap.yml
spring:
application:
name: foo
cloud:
config:
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
推薦在bootstrap.yml
or application.yml
里面配置spring.application.name
. 你可以通過設置spring.cloud.bootstrap.enabled=false
來禁用bootstrap
。
應用上下文層次結構
如果你通過SpringApplication
或者SpringApplicationBuilder
創建一個Application Context
,那么會為spring應用的Application Context
創建父上下文Bootstrap Context
。在Spring里有個特性,子上下文會繼承父類的property sources
and profiles
,所以main application context
相對於沒有使用Spring Cloud Config,會新增額外的property sources
。額外的property sources
有:
- “bootstrap” : 如果在
Bootstrap Context
掃描到PropertySourceLocator
並且有屬性,則會添加到CompositePropertySource。**Spirng Cloud Config就是通過這種方式來添加的屬性的**,詳細看源碼
ConfigServicePropertySourceLocator`。下面也也有一個例子自定義的例子。 - “applicationConfig: [classpath:bootstrap.yml]” ,(如果有
spring.profiles.active=production
則例如 applicationConfig: [classpath:/bootstrap.yml]#production): 如果你使用bootstrap.yml
來配置Bootstrap Context
,他比application.yml
優先級要低。它將添加到子上下文,作為Spring Boot應用程序的一部分。下文有介紹。
由於優先級規則,Bootstrap Context
不包含從bootstrap.yml
來的數據,但是可以用它作為默認設置。
你可以很容易的擴展任何你建立的上下文層次,可以使用它提供的接口,或者使用SpringApplicationBuilder
包含的方法(parent()
,child()
,sibling()
)。Bootstrap Context
將是最高級別的父類。擴展的每一個Context
都有有自己的bootstrap property source
(有可能是空的)。擴展的每一個Context
都有不同spring.application.name
。同一層層次的父子上下文原則上也有一有不同的名稱,因此,也會有不同的Config Server配置。子上下文的屬性在相同名字的情況下將覆蓋父上下文的屬性。
注意SpringApplicationBuilder
允許共享Environment
到所有層次,但是不是默認的。因此,同級的兄弟上下文不在和父類共享一些東西的時候不一定有相同的profiles
或者property sources
。
修改Bootstrap屬性配置
源碼位置BootstrapApplicationListener
。
String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
String configLocation = environment.resolvePlaceholders("${spring.cloud.bootstrap.location:}"); Map<String, Object> bootstrapMap = new HashMap<>();bootstrapMap.put("spring.config.name",configName); if(StringUtils.hasText(configLocation)){ bootstrapMap.put("spring.config.location", configLocation); }
bootstrap.yml
是由spring.cloud.bootstrap.name
(默認:”bootstrap”)或者spring.cloud.bootstrap.location
(默認空)。這些屬性行為與spring.config.*
類似,通過它的Environment
來配置引導ApplicationContext
。如果有一個激活的profile
(來源於spring.profiles.active
或者Environment
的Api構建),例如bootstrap-development.properties
就是配置了profile
為development
的配置文件.
覆蓋遠程屬性
property sources
被bootstrap context
添加到應用通常通過遠程的方式,比如”Config Server”。默認情況下,本地的配置文件不能覆蓋遠程配置,但是可以通過啟動命令行參數來覆蓋遠程配置。**如果需要本地文件覆蓋遠程文件,需要在遠程配置文件里設置授權 **
spring.cloud.config.allowOverride=true
(這個配置不能在本地被設置)。一旦設置了這個權限,你可以配置更加細粒度的配置來配置覆蓋的方式,
比如:
-
spring.cloud.config.overrideNone=true
覆蓋任何本地屬性 -
spring.cloud.config.overrideSystemProperties=false
僅僅系統屬性和環境變量
源文件見PropertySourceBootstrapProperties
自定義啟動配置
bootstrap context
是依賴/META-INF/spring.factories
文件里面的org.springframework.cloud.bootstrap.BootstrapConfiguration
條目下面,通過逗號分隔的Spring @Configuration
類來建立的配置。任何main application context
需要的自動注入的Bean可以在這里通過這種方式來獲取。這也是ApplicationContextInitializer
建立@Bean
的方式。可以通過@Order
來更改初始化序列,默認是”last”。
# spring-cloud-context-1.1.1.RELEASE.jar # spring.factories # AutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\ org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.cloud.bootstrap.BootstrapApplicationListener,\ org.springframework.cloud.context.restart.RestartListener # Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\ org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\ org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration
警告
小心,你添加的自定義BootstrapConfiguration類沒有錯誤的@ComponentScanned到你的主應用上下文,他們可能是不需要的。
使用一個另外的包不被@ComponentScan或者@SpringBootApplication注解覆蓋到。
bootstrap context
通過spring.factories
配置的類初始化的所有的Bean都會在SpingApplicatin啟動前加入到它的上下文里去。
自定義引導配置來源:Bootstrap Property Sources
默認的property source
添加額外的配置是通過配置服務(Config Server),你也可以自定義添加property source
通過實現PropertySourceLocator
接口來添加。你可以使用它加配置屬性從不同的服務、數據庫、或者其他。
- 下面是一個自定義的例子:
@Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {
@Override public PropertySource<?> locate(Environment environment) { return new MapPropertySource("customProperty", Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended")); }
Environment
被ApplicationContext
建立,並傳入property sources
(可能不同個profile
有不同的屬性),所以,你可以從Environment
尋找找一些特別的屬性。比如spring.application.name
,它是默認的Config Server property source
。
如果你建立了一個jar包,里面添加了一個META-INF/spring.factories
文件:
org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator
那么,”customProperty“的PropertySource
將會被包含到應用。