springcloud config配置读取优先级过程详解

情景描述

最近在修复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的情况下,外部源配置也比本地文件拥有更高的优先级。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解SpringCloud Config配置中心

    一.创建Config配置中心项目 1.添加依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> 2.启动类,需要添加@EnableConfigServer import org.springframework.boot.SpringApp

  • Spring Cloud Config Client超时及重试示例详解

    简介 有时客户端需要在 config server 无响应时进行重试,以给 config server 时间进行恢复.利用 spring 提供的重试组件,我们可以方便的配置重试机制,包括重试间隔,重试次数等.下面话不多说了,来一起看看详细的介绍吧. 项目源码 点击下载 为 web 项目添加依赖 开启客户端重试功能需要两个新依赖,spring-retry 和 spring-boot-starter-aop,把如下代码添加到 web 项目的 pom.xml 文件中: <dependency> &l

  • SpringCloud之分布式配置中心Spring Cloud Config高可用配置实例代码

    一.简介 当要将配置中心部署到生产环境中时,与服务注册中心一样,我们也希望它是一个高可用的应用.Spring Cloud Config实现服务端的高可用非常简单,主要有以下两种方式. 传统模式:不需要为这些服务端做任何额外的配置,只需要遵守一个配置规则,将所有的Config Server都指向同一个Git仓库,这样所有的配置内容就通过统一的共享文件系统来维护.而客户端在指定Config Server位置时,只需要配置Config Server上层的负载均衡设备地址即可, 就如下图所示的结构. 服

  • spring-cloud入门之spring-cloud-config(配置中心)

    前言 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件:spring-cloud-config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中. 本节主要演示怎么用Git仓库作为配置源. 开源地址:https://github.com/bigbeef 创建配置项目 在github中创建一个项目,专门用来保存我们所有项目的配置文件,项目是我的项目结构 配置项目地址:https://github.com/bigbeef/

  • Spring Cloud Config RSA简介及使用RSA加密配置文件的方法

    Spring Cloud 为开发人员提供了一系列的工具来快速构建分布式系统的通用模型 .例如:配置管理.服务发现.断路由.智能路由.微代理.控制总线.一次性Token.全局锁.决策竞选.分布式session.集群状态等等.分布式系统的协助需要一大堆的模型,使用Spring Cloud开发者能快速的建立支持实现这些模式的服务和应用程序.他们将适用于任何分布式环境,无论是开发者的个人电脑还是生产环境,还是云平台. 特性 Spring Cloud 专注于提供良好开箱即用的典型方案和可扩展方式. 分布式

  • 利用Spring Cloud Config结合Bus实现分布式配置中心的步骤

    概述 假设现在有个需求: 我们的应用部署在10台机器上,当我们调整完某个配置参数时,无需重启机器,10台机器自动能获取到最新的配置. 如何来实现呢?有很多种,比如: 1.将配置放置到一个数据库里面,应用每次读取配置都是直接从DB读取.这样的话,我们只需要做一个DB变更,把最新的配置信息更新到数据库即可.这样无论多少台应用,由于都从同一个DB获取配置信息,自然都能拿到最新的配置. 2.每台机器提供一个更新配置信息的updateConfig接口,当需要修改配置时,挨个调用服务器的updateConf

  • spring cloud学习入门之config配置教程

    前言 本文主要给大家分享了关于spring cloud的入门教程,主要介绍了config配置的相关内容,下面话不多说了,来一起看看看详细的介绍吧. 简介 Spring cloud config 分为两部分 server client config-server 配置服务端,服务管理配置信息 config-client 客户端,客户端调用server端暴露接口获取配置信息 config-server 创建config-server 首先创建config-server工程. 文件结构: ├── co

  • 详解spring cloud config实现datasource的热部署

    关于spring cloud config的基本使用,前面的博客中已经说过了,如果不了解的话,请先看以前的博客 spring cloud config整合gitlab搭建分布式的配置中心 spring cloud config分布式配置中心的高可用 今天,我们的重点是如何实现数据源的热部署. 1.在客户端配置数据源 @RefreshScope @Configuration// 配置数据源 public class DataSourceConfigure { @Bean @RefreshScope

  • springcloud config配置读取优先级过程详解

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

  • Spring Cloud应用实现配置自动刷新过程详解

    这篇文章主要介绍了Spring Cloud应用实现配置自动刷新过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 通过spring cloud 的消息总线,将配置github 等源代码仓库的变更通知到spring cloud 的所有组件. spring-bus 需要用到rabbitmq ,所以需要提前准备rabbitmq消息队列环境 配置中心调整 1.配置中心配置引用pom <dependency> <groupId>org.

  • NodeJS配置CORS实现过程详解

    跨域问题主要在header上下功夫 首先提供一个w3c的header定义 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 再提供一个网友提供的header详解 http://kb.cnblogs.com/page/92320/ 这两个有助于帮助大家理解header的类型和作用, 但是遗憾的是跨域相关的两个header属性我都没有找到相关的定义, 下面直接告诉大家 1是Access-Control-Allow-Origin 允许的域 2

  • Java手动配置线程池过程详解

    线程池中,常见有涉及到的: ExecutorService executorService = Executors.newSingleThreadExecutor(); ExecutorService executorService1 = Executors.newCachedThreadPool(); ExecutorService executorService2 = Executors.newFixedThreadPool(3); 关于Executors和ExecutorService从记

  • 基于nexus3配置Python仓库过程详解

    搭建Python私服,我们依旧使用nexus3. 与其他私服一样的,Python私服同样有三种类型: hosted : 本地存储,便于开发者将个人的一些包上传到私服中proxy : 提供代理其他仓库的类型,如豆瓣的pypi仓库group : 组类型,实质作用是组合多个仓库为一个对外的地址 那么就来一个一个创建. 1,创建blob存储 为其创建一个单独的存储空间. 2,创建hosted类型的pypiName: 定义一个名称local-pypiStorage Blob store,我们下拉选择前面创

  • SPRINGBOOT读取PROPERTIES配置文件数据过程详解

    这篇文章主要介绍了SPRINGBOOT读取PROPERTIES配置文件数据过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.使用@ConfigurationProperties来读取 1.Coffer entity @Configuration @ConfigurationProperties(prefix = "coffer") @PropertySource("classpath:config/coffer.p

  • Spring cloud config集成过程详解

    这篇文章主要介绍了spring cloud config集成过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Spring Cloud Config 分为 Config Server: 分布式配置中心,是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息 Config Client: 通过指定配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息 Spring boot版本2.1.8.

  • SpringCloud搭建netflix-eureka微服务集群的过程详解

    1.打开官网稍微学习一下,了解一下spring cloud是个什么东西,大概有哪些组件等 https://spring.io/projects/spring-cloud https://docs.spring.io/spring-cloud-netflix/docs/current/reference/html/ 2.新建项目 打开网址:https://start.spring.io/ 选择需要引入的组件,然后下载下来即可 3.更改项目结构 为了测试的方便,需将项目结构更改为多模块的项目. 步骤

  • C++ Qt之halcon读取像素项目过程详解

    项目环境:win10,qt5.14,halcon20 功能:1.读取指定图像2.读取指定目录下的图像 项目配置文件 QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked depreca

  • SpringBoot配置自定义拦截器实现过程详解

    目录 1. HttpServletRequest包装类 2. 使用Filter将request传递下去 3. 添加拦截器 4. 全局异常处理器 5. 配置拦截器 1. HttpServletRequest包装类 因为HttpServletRequest只能读取一次,所以需要对request进行包装,变成可重复读的request. package net.lesscoding.interceptor; import javax.servlet.ReadListener; import javax.

随机推荐