一.简述
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
将会被包含到应用。