Categories
Uncategorized

springcloud config configuration read priority

Scenario Description

In a recent repair Eureka static pages to load no defects, eventually found a remote GIT repository access method static resources allocated to disabled (spring.resources.add-mappings = false). While the final configuration items directly modify this remote GIT repository to solve (spring.resources.add-mappings = true), but which involved a configuration read priority we must look back at the good

springcloud config read warehouse configuration

A remote repository configured to read through the config client module, only need to configure the following properties in the file can be 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

Which will go to a GET request http: // localhost: 8888 / eureka / dev address configuration thereby pull down.
    Of course, the above-mentioned address API also need to be deployed to access the server config server before calling service, specific details are not carried out

Read priority external source

We all know that spring configuration management attributes are stored in the Enviroment object, with regard to the general project StandardEnvironment, for example, can be configured to store the order listed below

Overall

source

Explanation

Incoming main function parameter list

JDK list of properties, property operating system, beginning with -D VM properties, etc.

Environment attributes, e.g. JAVA_HOME / M2_HOME

Profiles

For example application.yml

key
1 commandLineArgs Program arguments
2 systemProperties System.getProperties()
3 systemEnvironment System.getEnv()
4 ${file_name}
5 defaultProperties SpringApplicationBuilder#properties()

Then the configuration is stored remotely read what position should be placed above it?
    We all know boostrap context to facilitate integration of third-party external source by exposure org.springframework.cloud.bootstrap.config.PropertySourceLocator read interface configuration, such as mentioned herein config client module in org.springframework.cloud.config.client .ConfigServicePropertySourceLocator implementation class.

But eventually the external source and inserted into the read configuration Environment objects are accomplished by org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration class.

PropertySourceBootstrapConfiguration

Such is the implementation class ApplicationContextInitializer interface, read cloud source all know, these are called in when a subclass of context initialization, we mainly look initialize () method of its replication

    @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);
        }
    }

Direct observation of the corresponding insertPropertySources () method

    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);
        }
    }

As described above under the code summary
    1. The above configuration attributes are mapped to PropertySourceBootstrapProperties entity class, and wherein the default values ​​listed below

Attributes

Defaults

Explanation

Whether an external source configuration may be covered

If the external source arranged not to cover any source

Whether an external source may be arranged to cover local property

spring.cloud.config.allow-override true
spring.cloud.config.override-none false
spring.cloud.config.override-system-properties true

2. The value of the corresponding attribute for the corresponding external source read priority Environment object, listed below

Attributes

Read priority

highest

Maximum (default)

lowest

Context no spring properties systemEnvironment

lowest

systemEnvironment spring context attributes && spring.cloud.config.override-system-properties = false

After systemEnvironment

systemEnvironment spring context attributes && spring.cloud.config.override-system-properties = false

Before systemEnvironment

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

I.e. the default configuration attribute read external source priority is the highest.
    And in addition to the case where spring.cloud.config.override-none = true, the read external source other cases a higher priority than the local configuration files.
    Note: It is noted that, if the user wants to duplicate the properties described above, in the bootstrap.yml | application.yml profile is invalid, in accordance with custom source code analysis is only a PropertySourceLocator interface class and placed in the corresponding spring.factories file to take effect.

Custom interfaces PropertySourceLocator

For described above, assuming that there is such a scene, a remote warehouse configurations are public, we can not change it, we are only in the project to rewrite the appropriate configuration to achieve compatibility purposes. Then the user will need to write custom interfaces the
    1. Write a class that implements the interface 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 customMap = new HashMap<>(2);
        // 远程仓库此配置为false,本地进行复写
        customMap.put(OVERRIDE_ADD_MAPPING, "true");

        return new MapPropertySource("custom", customMap);
    }
}

2. Write 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. Create a META-INF \ spring.factories files in src \ main \ resources directory

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

4. Run the main function to

summary

By default, the external source configuration has the highest priority. In the case of spring.cloud.config.override-none = false, the external source configuration also has a higher priority than the local file.

Leave a Reply