Spring Boot 核心配置文件 bootstrap & application
部分內容原文地址:博客園-JackYang:SpringCloud入門之常用的配置文件 application.yml和 bootstrap.yml區別
Spring Boot 中有以下兩種配置文件
- bootstrap (.yml 或者 .properties)
- application (.yml 或者 .properties)
1、SpringBoot bootstrap配置文件不生效問題
單獨使用SpringBoot,發現其中的bootstrap.properties文件無法生效,改成yaml格式也無濟於事。
最後調查發現原來是因爲SpringBoot本身並不支持,需要和Spring Cloud 的組件結合——只有加上Spring Cloud Context依賴才能生效。
即在pom中引入:
<!--需要引入該jar才能使bootstrap配置文件生效-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
2、bootstrap/ application 的區別
在 Spring Boot 中有兩種上下文,一種是 bootstrap, 另外一種是 application, bootstrap 是應用程序的父上下文,也就是說 bootstrap 加載優先於 applicaton。bootstrap 主要用於從額外的資源來加載配置信息,還可以在本地外部配置文件中解密屬性。這兩個上下文共用一個環境,它是任何Spring應用程序的外部屬性的來源。bootstrap 裏面的屬性會優先加載,它們默認也不能被本地相同配置覆蓋。
因此,對比 application 配置文件,bootstrap 配置文件具有以下幾個特性。
- boostrap 由父 ApplicationContext 加載,比 applicaton 優先加載
- boostrap 裏面的屬性不能被覆蓋
3、bootstrap/ application 的應用場景
application 配置文件這個容易理解,主要用於 Spring Boot 項目的自動化配置。
bootstrap 配置文件有以下幾個應用場景。
- 使用 Spring Cloud Config 配置中心時,這時需要在 bootstrap 配置文件中添加連接到配置中心的配置屬性來加載外部配置中心的配置信息;
- 一些固定的不能被覆蓋的屬性
- 一些加密/解密的場景;
技術上,bootstrap.yml 是被一個父級的 Spring ApplicationContext 加載的。這個父級的 Spring ApplicationContext是先加載的,在加載application.yml 的 ApplicationContext之前。
爲何需要把 config server 的信息放在 bootstrap.yml 裏?
當使用 Spring Cloud 的時候,配置信息一般是從 config server 加載的,爲了取得配置信息(比如密碼等),你需要一些提早的引導配置。因此,把 config server 信息放在 bootstrap.yml,用來加載在這個時期真正需要的配置信息。
4、高級使用場景
4.1 啓動上下文
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
。
4.2 應用上下文層次結構
如果你通過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。
4.3 修改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的配置文件.
4.3.1 覆蓋遠程屬性
property sources被bootstrap context 添加到應用通常通過遠程的方式,比如”Config Server”。默認情況下,本地的配置文件不能覆蓋遠程配置,但是可以通過啓動命令行參數來覆蓋遠程配置。如果需要本地文件覆蓋遠程文件,需要在遠程配置文件裏
4.3.2 設置授權
spring.cloud.config.allowOverride=true(這個配置不能在本地被設置)。一旦設置了這個權限,你可以配置更加細粒度的配置來配置覆蓋的方式,
比如:
- spring.cloud.config.overrideNone=true 覆蓋任何本地屬性
- spring.cloud.config.overrideSystemProperties=false 僅僅系統屬性和環境變量
源文件見PropertySourceBootstrapProperties.
4.4 自定義啓動配置
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啓動前加入到它的上下文裏去。
4.5 自定義引導配置來源: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將會被包含到應用。