情景描述

最近在修复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. LoRaWAN_stack移植笔记 (二)_GPIO

    stm32相关的配置 由于例程使用的主控芯片为STM32L151C8T6,而在本设计中使用的主控芯片为STM32L051C8T6,内核不一样,并且Cube库相关的函数接口及配置也会有不同,所以芯片的驱 ...

  2. v语言怎么玩

    直接上github: https://github.com/vlang/v 前戏 大概是在6月份的时候,在github上看到了这个玩意,我以为是??? 我下意识的去查了一下有没有人在讨论这个语言,但是 ...

  3. 操作微信-itchat库的安装

    基于pyCharm开发环境,在CMD控制台输入:pip install itchat      等待安装...... Microsoft Windows [版本 6.1.7601]版权所有 (c) 2 ...

  4. SQL语言分类之DDL、DML、DCL、DQL

    SQL 语言共分为四大类: 数据控制语言 DCL 数据定义语言 DDL 数据操纵语言 DML 数据查询语言 DQL 一.数据控制语言 DCL 1.1 作用 用来设置或更改数据库用户或角色权限的语句,并 ...

  5. HTML连载34-背景关联和缩写以及插图图片和背景图片的区别

    一.背景属性缩写的格式 1.backgound:背景颜色  背景图片  平铺方式  关联方式  定位方式 2.注意点: 这里的所有值都可以省略,但是至少需要一个 3.什么是背景关联方式 默认情况下,背 ...

  6. 剑指Offer(二十八):数组中出现次数超过一半的数字

    剑指Offer(二十八):数组中出现次数超过一半的数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...

  7. 7.解决在python中用selenium启动FireFox浏览器启动不了的方法

    首次在利用python中的selenium启动FireFox浏览器时可能碰到如下问题 当输入如下代码时: from selenium import webdriver brower=webdriver ...

  8. 分享一个赚钱方法:用趣分类app在家轻松赚钱

    什么是趣分类 近期,垃圾分类是社会各界和广大市民关心的一个热门话题,随着垃圾分类工作的推进,各地都掀起学习垃圾分类的热潮.为了我们的美好生活,打响"垃圾分类"这场硬仗刻不容缓.据了 ...

  9. CF990C Bracket Sequences Concatenation Problem 思维 第五道 括号经典处理题目

     Bracket Sequences Concatenation Problem time limit per test 2 seconds memory limit per test 256 meg ...

  10. 字符串的api (基础)

    一.基础 1.字符串.charAt(index) 根据下标获取字符串的某一个字符 应用: 判断字符串的首字母是否大写 任意给定的一串字母,统计字符串里面的大写字母和小写字母的个数 2.字符串.inde ...