情景描述

最近在修复Eureka的静态页面加载不出的缺陷时,最终发现是远程GIT仓库将静态资源访问方式配置给禁用了(spring.resources.add-mappings=false)。虽然最后直接修改远程GIT仓库的此配置项给解决了(spring.resources.add-mappings=true),但是从中牵涉出的配置读取优先级我们必须好好的再回顾下

springcloud config读取仓库配置

通过config client模块来读取远程的仓库配置,只需要在boostrap.properties文件中配置如下属性即可

spring.application.name=eureka

spring.cloud.config.uri=http://localhost:8888
spring.cloud.config.name=dev
spring.cloud.config.username=dev
spring.cloud.config.password=dev

其就会以GET方式去请求http://localhost:8888/eureka/dev地址从而将配置拉取下来。

当然上述的API地址也是需要被访问服务器部署了config server服务方可调用,具体的细节就不展开了

外部源读取优先级

我们都知道spring的配置属性管理均是存放在Enviroment对象中,就以普通项目StandardEnvironment为例,其配置的存放顺序可罗列如下

顺位 key 来源 说明
1 commandLineArgs 传入main函数的参数列表 Program arguments
2 systemProperties System.getProperties() JDK属性列表、操作系统属性、-D开头的VM属性等
3 systemEnvironment System.getEnv() 环境属性,例如JAVA_HOME/M2_HOME
4 ${file_name} 配置文件 例如application.yml
5 defaultProperties SpringApplicationBuilder#properties()

那么远程读取的配置的存放应该放在上述的哪个位置呢?

我们都知道boostrap上下文通过暴露org.springframework.cloud.bootstrap.config.PropertySourceLocator接口来方便集成第三方的外部源配置读取,比如本文提及的config client模块中的org.springframework.cloud.config.client.ConfigServicePropertySourceLocator实现类。

但最终将外部源配置读取以及插入至Environment对象中则是通过org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration类来完成的。

PropertySourceBootstrapConfiguration

此类也是ApplicationContextInitializer接口的实现类,阅读过cloud源码的都知道,此类被调用是在子类上下文初始化的时候,我们主要看下其复写的initialize()方法

	@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
CompositePropertySource composite = new CompositePropertySource(
BOOTSTRAP_PROPERTY_SOURCE_NAME);
// 对在boostrap上下文类型为PropertySourceLocator的bean集合进行排序
AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true;
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySourceLocator locator : this.propertySourceLocators) {
PropertySource<?> source = null;
// 读取外部配置源
source = locator.locate(environment);
if (source == null) {
continue;
}
logger.info("Located property source: " + source);
composite.addPropertySource(source);
empty = false;
}
if (!empty) {
MutablePropertySources propertySources = environment.getPropertySources();
String logConfig = environment.resolvePlaceholders("${logging.config:}");
LogFile logFile = LogFile.get(environment);
if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
}
// 插入至Environment环境对象中
insertPropertySources(propertySources, composite);
reinitializeLoggingSystem(environment, logConfig, logFile);
setLogLevels(applicationContext, environment);
handleIncludedProfiles(environment);
}
}

直接观察对应的insertPropertySources()方法

	private void insertPropertySources(MutablePropertySources propertySources,
CompositePropertySource composite) {
// 外部源配置集合
MutablePropertySources incoming = new MutablePropertySources();
incoming.addFirst(composite);
PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties();
// 从外部源配置源集合中读取PropertySourceBootstrapProperties的相关属性
// 例如spring.cloud.config.overrideSystemProperties等属性
Binder.get(environment(incoming)).bind("spring.cloud.config",
Bindable.ofInstance(remoteProperties));
// spring.cloud.config.allow-override=false或者spring.cloud.config.override-none=false且spring.cloud.config.override-system-properties=true
if (!remoteProperties.isAllowOverride() || (!remoteProperties.isOverrideNone()
&& remoteProperties.isOverrideSystemProperties())) {
propertySources.addFirst(composite);
return;
}
// spring.cloud.config.override-none=true则处于最低读取位
if (remoteProperties.isOverrideNone()) {
propertySources.addLast(composite);
return;
}
// 根据spring.cloud.config.override-system-properties属性判断是放在systemProperties前还是后
if (propertySources
.contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) {
if (!remoteProperties.isOverrideSystemProperties()) {
propertySources.addAfter(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
composite);
}
else {
propertySources.addBefore(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
composite);
}
}
else {
propertySources.addLast(composite);
}
}

对上述的代码描述作下总结

1.上述的配置属性均会映射到PropertySourceBootstrapProperties实体类中,且其中的默认值罗列如下

属性 默认值 说明
spring.cloud.config.allow-override true 外部源配置是否可被覆盖
spring.cloud.config.override-none false 外部源配置是否不覆盖任何源
spring.cloud.config.override-system-properties true 外部源配置是否可覆盖本地属性

2.针对相应的属性的值对应的外部源在Environment对象中的读取优先级,罗列如下

属性 读取优先级
spring.cloud.config.allow-override=false 最高
spring.cloud.config.override-none=false&&spring.cloud.config.override-system-properties=true 最高(默认)
spring.cloud.config.override-none=true 最低
spring上下文无systemEnvironment属性 最低
spring上下文有systemEnvironment属性 && spring.cloud.config.override-system-properties=false 在systemEnvironment之后
spring上下文有systemEnvironment属性 && spring.cloud.config.override-system-properties=false 在systemEnvironment之前

即默认情况下,外部源的配置属性的读取优先级是最高的。

且除了spring.cloud.config.override-none=true的情况下,其他情况下外部源的读取优先级均比本地配置文件高。

Note:值得注意的是,如果用户想复写上述的属性,则放在bootstrap.yml|application.yml配置文件中是无效的,根据源码分析只能是自定义一个PropertySourceLocator接口实现类并放置在相应的spring.factories文件中方可生效。

自定义PropertySourceLocator接口

针对上文描述,假设有这么一个场景,远程仓库的配置都是公有的,我们也不能修改它,我们只在项目中去复写相应的配置以达到兼容的目的。那么用户就需要自定义去编写接口了

1.编写PropertySourceLocator接口实现类

package com.example.configdemo.propertysource;

import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource; import java.util.HashMap;
import java.util.Map; /**
* @author nanco
* @create 19/9/22
* @description 自定义的PropertySourceLocator的顺序应该要比远程仓库读取方式要优先
* @see org.springframework.cloud.config.client.ConfigServicePropertySourceLocator
*/
@Order(value = Ordered.HIGHEST_PRECEDENCE + 1)
public class CustomPropertySourceLocator implements PropertySourceLocator { private static final String OVERRIDE_ADD_MAPPING = "spring.resources.add-mappings"; @Override
public PropertySource<?> locate(Environment environment) { Map<String, Object> customMap = new HashMap<>(2);
// 远程仓库此配置为false,本地进行复写
customMap.put(OVERRIDE_ADD_MAPPING, "true"); return new MapPropertySource("custom", customMap);
}
}

2.编写BootstrapConfiguration

package com.example.configdemo.propertysource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* @author nanco
* @create 19/9/22
*/
@Configuration
public class CustomBootstrapConfiguration { @Bean("customPropertySourceLocator")
public CustomPropertySourceLocator propertySourceLocator() {
return new CustomPropertySourceLocator();
}
}

3.在src\main\resources目录下创建META-INF\spring.factories文件

# Bootstrap components
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.example.configdemo.propertysource.CustomBootstrapConfiguration

4.运行main函数即可

小结

默认情况下,外部源配置拥有最高的优先级。在spring.cloud.config.override-none=false的情况下,外部源配置也比本地文件拥有更高的优先级。

springcloud config配置读取优先级的更多相关文章

  1. springboot用@Autowired和@PostConstruct注解把config配置读取到bean变成静态方法

    springboot用@Autowired和@PostConstruct注解把config配置读取到bean变成静态方法 @SpringBootApplication public class Sen ...

  2. spring-cloud config配置中心

    这里那些概念不说,主要是记录下spring cloud config配置中心的服务端和客户端的一个demo. 服务端即提供统一配置文件 客户端即从服务端读取配置 1.新建一个spring boot项目 ...

  3. SpringCloud Config(配置中心)实现配置自动刷新(十六)

    一.实现原理 1.ConfigServer(配置中心服务端)从远端git拉取配置文件并在本地git一份,ConfigClient(微服务)从ConfigServer端获取自己对应 配置文件: 2.当远 ...

  4. SpringCloud 进阶之分布式配置中心(SpringCloud Config)

    1. SpringCloud Config SpringCLoud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用 的所有环境提供了一个中心化的外部配置; ...

  5. SpringCloud的入门学习之概念理解、Config配置中心

    1.SpringCloud Config分布式配置中心.分布式系统面临的配置问题. 答:微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务.由于每个 ...

  6. SpringCloud学习笔记(九):SpringCloud Config 分布式配置中心

    概述 分布式系统面临的-配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务.由于每个服务都需要必要的配置信息才能运行,所以一套集中式的.动 ...

  7. 深入探究.Net Core Configuration读取配置的优先级

    前言     在之前的文章.Net Core Configuration源码探究一文中我们曾解读过Configuration的工作原理,也.Net Core Configuration Etcd数据源 ...

  8. SpringCloud Netflix (六):Config 配置中心

    ------------恢复内容开始------------ SpringCloud Config 配置中心 Config 配置中心 Spring Cloud Config为分布式系统中的外部化配置提 ...

  9. SpringCloud config native 配置

    1.概述 最近项目使用springCloud 框架,使用config搭建git作为配置中心. 在私有化部署中,出现很多比较麻烦的和鸡肋的设计. 每次部署都需要安装gitlab 有些环境安装完gitla ...

随机推荐

  1. csdn论坛页抓取

    抓取csdn论坛 实现功能 获取论坛分类所有链接,并拼接成推荐精华页的完成的链接 获取推荐精华页的帖子状态,赏分,帖子标题,作者,发布时间,回复量,查看量,最后发表时间 置顶内容不爬取,只打印置顶内容 ...

  2. Luogu P5490 扫描线

    模板题,想象一条线从左边扫到右边,只有在矩阵边界才会产生影响,所以我们离散化缩小数据范围,再用线段树维护扫描线上的情况,得出结果 #include<bits/stdc++.h> #defi ...

  3. Linux设备驱动程序学习----3.模块的编译和装载

    模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...

  4. DNS域名解析服务及其配置

    一.背景 到 20 世纪 70 年代末,ARPAnet 是一个拥有几百台主机的很小很友好的网络.仅需要一个名为 HOSTS.TXT 的文件就能容纳所有需要了解的主机信息:它包含了所有连接到 ARPAn ...

  5. Spring Cloud Zuul的动态路由怎样做?集成Nacos实现很简单

    一.说明 网关的核心概念就是路由配置和路由规则,而作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,是尽量要避免重启的,所以实现动态路由是非常有必要的:本文主要介绍实现的思路,并且以Na ...

  6. MSIL实用指南-struct的生成和操作

    struct(结构)是一种值类型,用于将一组相关的信息变量组织为一个单一的变量实体.所有的结构都继承自System.ValueType类,因此是一种值类型,也就是说,struct实例分配在线程的堆栈( ...

  7. 从零开始搭建Java开发环境第二篇:如何在windows10里安装MySQL

    1 下载安装包 1.1 压缩包 https://dev.mysql.com/downloads/mysql/ [外链图片转存失败(img-oesO8K09-1566652568838)(data:im ...

  8. CAS及其ABA问题

    CAS.volatile是JUC包实现同步的基础.Synchronized下的偏向锁.轻量级锁的获取.释放,lock机制下锁的获取.释放,获取失败后线程的入队等操作都是CAS操作锁标志位.state. ...

  9. Mybatis案例升级版——小案例大道理

    纯Mybatis案例升级版——小案例大道理 前言: 这几天看了一本书<原则>,在上面看到了一句话叫“每个人都把自己眼界的局限当成世界的局限”,大学生是

  10. AC自动机 数组实现

    AC自动机的实现原理是KMP + 字典树. 学AC自动机之前要先去学KMP 和 字典树. 第一步先构建一个字典树. void Insert(){ , len = strlen(str); ; i &l ...