• 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.在srcmain esources目录下创建META-INFspring.factories文件

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

    4.运行main函数即可

    小结

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

  • 相关阅读:
    ubuntu挂载群晖共享文件
    200. 岛屿数量_中等_不再记笔记了
    733. 图像渲染_简单_矩阵
    46. 全排列_中等_模拟
    37. 解数独_困难_矩阵
    1041. 困于环中的机器人_中等_模拟
    946. 验证栈序列
    415. 字符串相加_简单_模拟
    164. 最大间距_数组_困难
    215. 数组中的第K个最大元素_中等_数组
  • 原文地址:https://www.cnblogs.com/question-sky/p/11580365.html
Copyright © 2020-2023  润新知