SpringApplication run方法第四步解析(三)[(未完结,暂搁置)]

前言

之前我们分析了SpringApplication#run⽅法的前3步.在这⾥我们分析第4步-->创建⼀个DefaultApplicationArguments对象,调⽤prepareEnvironment⽅法。

本篇涉及到的代码:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        ......

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);

           ......
    }

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args)流程简述:

 DefaultApplicationArguments有两个对象:

private final DefaultApplicationArguments.Source source;
private final String[] args;

1、创建一个DefaultApplicationArguments对象,该构造方法,会调用

解析args入参,放到该对象的source属性中,这个source是一个DefaultApplicationArguments.Source对象。

this.source = new DefaultApplicationArguments.Source(args);

2、命令行参数会放到CommandLineArgs对象中(DefaultApplicationArguments.Source是CommandLineArgs的子类),以"--"开头的参数都会放到optionArgs属性,该属性是一个Hashmap;其他参数会放到nonOptionArgs属性中,该属性是一个ArrayList。

3、通知所有观察者。最终走到org.springframework.boot.env.EnvironmentPostProcessor,找到对应的SpringApplicationJsonEnvironmentPostProcessor类和CloudFoundryVcapEnvironmentPostProcessor类,执行他们的postProcessEnvironment方法。
 

 

 DefaultApplicationArguments.Source继承结构图:

 

 分析

 1. 创建DefaultApplicationArguments.将启动时的参数传⼊到其构造器中.其构造器如下:

public DefaultApplicationArguments(String[] args) {
        Assert.notNull(args, "Args must not be null");
        this.source = new DefaultApplicationArguments.Source(args);
        this.args = args;
    }

Source类的定义:

private static class Source extends SimpleCommandLinePropertySource {
        Source(String[] args) {
            super(args);
        }

        public List<String> getNonOptionArgs() {
            return super.getNonOptionArgs();
        }

        public List<String> getOptionValues(String name) {
            return super.getOptionValues(name);
        }
    }

在Source的构造器中调⽤了⽗类的SimpleCommandLinePropertySource的构造器.如下:

public SimpleCommandLinePropertySource(String... args) {
        super((new SimpleCommandLineArgsParser()).parse(args));
    }

实例化了SimpleCommandLineArgsParser并调⽤其parse⽅法进⾏解析参数.代码如下:

public CommandLineArgs parse(String... args) {
        //创建CommandLineArgs对象
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        String[] var3 = args;
        int var4 = args.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            //进循环,判断是否以--开头
            String arg = var3[var5];
            if (arg.startsWith("--")) {
                //如果是就截取,截取长度是参数长度,如果命令是--spring,那么就从s开始截取,包括s
                String optionText = arg.substring(2, arg.length());
                String optionValue = null;
                String optionName;
                //如果匹配到了=号,截取=号左边做optionName,右边做optionValue
                if (optionText.contains("=")) {
                    optionName = optionText.substring(0, optionText.indexOf("="));
                    optionValue = optionText.substring(optionText.indexOf("=") + 1, optionText.length());
                } else {
                    //如果没有=号,optionName 直接就是截取的optionText
                    optionName = optionText;
                }

                if (optionName.isEmpty() || optionValue != null && optionValue.isEmpty()) {
                    throw new IllegalArgumentException("Invalid argument syntax: " + arg);
                }
                 //这里将解析的参数添加到上面创建的CommandLineArgs对象中,该对象中有一个Map<String, List<String>>来存放
                commandLineArgs.addOptionArg(optionName, optionValue);
            } else {
                 //不是--开头就是直接添加到非选项参数
                commandLineArgs.addNonOptionArg(arg);
            }
        }

        return commandLineArgs;
    }

逻辑很简单,⾸先初始化了CommandLineArgs.然后遍历args.如果args是--开头的,就加⼊OptionArg中,否
则加⼊到NonOptionArg中。

 

解析完毕后,接着调⽤CommandLinePropertySource的构造器,代码如下:

public static final String COMMAND_LINE_PROPERTY_SOURCE_NAME = "commandLineArgs";
public CommandLinePropertySource(T source) {
    super(COMMAND_LINE_PROPERTY_SOURCE_NAME, source);
}

EnumerablePropertySource的构造器如下:

public EnumerablePropertySource(String name, T source) {
    super(name, source);
}

PropertySource 构造器如下:

public PropertySource(String name, T source) {
    Assert.hasText(name, "Property source name must contain at least one character");
    Assert.notNull(source, "Property source must not be null");
    this.name = name;
    this.source = source;
}

⾄此DefaultApplicationArguments初始化完毕。

2. DefaultApplicationArguments初始化完毕后,调⽤SpringApplication#prepareEnvironment.代码如下:
 

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments)流程简述:

1、获取或创建environment,如果this.webEnvironment为true,则new StandardServletEnvironment()返回,否则new StandardEnvironment();

2、配置环境变量,分为两个部分,配置ProperSources和配置Profiles。

    a.配置ProperSources

主要是配置environment.getPropertySources()的对象。如果addCommandLineProperties为true并且有命令参数,分两步骤⾛:第⼀步存在commandLineArgs则继续设置属性;第⼆步commandLineArgs不存在则在头部添加commandLineArgs。
    b.配置Profiles

判断this.activeProfiles是否为空,不为空获取''spring.profiles.active"的property参数,添加到activeProfiles属性中。

再调用environment#setActiveProfiles方法,这种激活的配置文件。

3、配置监听器。(做的事太多,还不了解)

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		//1、 Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
        // 2. 配置环境的信息,applicationArguments.getSourceArgs()是命令行参数
		configureEnvironment(environment, applicationArguments.getSourceArgs());
        // 3. 通知所有的观察者,环境已经准备好了
		listeners.environmentPrepared(environment);
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}

代码做了3件事:
1. 获取或者创建ConfigurableEnvironment
2. 配置ConfigurableEnvironment
3. 通知所有的观察者,发送ApplicationEnvironmentPreparedEvent事件.
 

3. 获取或者创建ConfigurableEnvironment调⽤的是getOrCreateEnvironment⽅法.代码如下:

private ConfigurableEnvironment getOrCreateEnvironment() {
        // 1. 如果environment不为空则直接返回
		if (this.environment != null) {
			return this.environment;
		}
        // 2. 如果是web环境则直接实例化StandardServletEnvironment类
		if (this.webEnvironment) {
			return new StandardServletEnvironment();
		}
        // 3. 如果不是web环境则直接实例化StandardEnvironment类
		return new StandardEnvironment();
	}

⾸先判断environment是否为空,如果不为空直接返回,否则 如果是web环境则直接实例化StandardServletEnvironment,否则返回StandardEnvironment.
⼀般创建的是StandardServletEnvironment.
StandardServletEnvironment类的继承结构如下:

在StandardServletEnvironment实例化时,会触发AbstractEnvironment实例化.⽽在AbstractEnvironment的构造器中会调⽤customizePropertySources⽅法.代码如下:

public AbstractEnvironment() {
        this.propertySources = new MutablePropertySources(this.logger);
        this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
        this.customizePropertySources(this.propertySources);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Initialized " + this.getClass().getSimpleName() + " with PropertySources " + this.propertySources);
        }

    }

⽽在StandardServletEnvironment中的customizePropertySources⽅法如下:

 protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
        propertySources.addLast(new StubPropertySource("servletContextInitParams"));
        if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
            propertySources.addLast(new JndiPropertySource("jndiProperties"));
        }

        super.customizePropertySources(propertySources);
    }

在该⽅法中添加了servletConfigInitParams,servletContextInitParams,jndiProperties对应的Source. 在笔者的demo环境中, jndiProperties没有添加进去.
 

然后调⽤其StandardEnvironment#customizePropertySources⽅法.添加MapPropertySource,SystemEnvironmentPropertySource.代码如下:

protected void customizePropertySources(MutablePropertySources propertySources
) {
    propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
    propertySources.addLast(new   SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

4. 配置ConfigurableEnvironment,调⽤的是SpringApplication#configureEnvironment⽅法.代码如下:

protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

做了2件事:
1. 配置PropertySources
2. 配置Profiles
configurePropertySources⽅法如下:
 

protected void configurePropertySources(ConfigurableEnvironment environment,
			String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
        // 1. 如果defaultProperties不为空,则继续添加defaultProperties
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(
					new MapPropertySource("defaultProperties", this.defaultProperties));
		}
        // 2. 如果addCommandLineProperties为true并且有命令参数,
        // 分两步骤⾛:第⼀步存在commandLineArgs则继续设置属性;第⼆步commandLineArgs不存在则在头部添加commandLineArgs
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(new SimpleCommandLinePropertySource(
						name + "-" + args.hashCode(), args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

做了2件事:
1. 如果defaultProperties不为空,则继续添加defaultProperties
在当前环境下defaultProperties没有添加进去. 2. 如果addCommandLineProperties为true并且有命令参数, 分两步骤⾛:第⼀步存在commandLineArgs则继续设置属性;第⼆步commandLineArgs不存在则在头部添加commandLineArgs

那么该⽅法执⾏完毕后,MutablePropertySources类中propertySourceList已经存在的属性为:
commandLineArgs、 servletConfigInitParams、 servletContextInitParams、 jndiProperties(如果存在)、 systemProperties、 systemEnvironment、 defaultProperties(如果存在)
 

配置Profiles,调⽤的是SpringApplication#configureProfiles⽅法.代码如下:

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
		environment.getActiveProfiles(); // ensure they are initialized
		// But these ones should go first (last wins in a property key clash)
		Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
	}

做了3件事:
1. 调⽤AbstractEnvironment#getActiveProfiles获得Profile的配置.Profile配置项为spring.profiles.active
2. 调⽤AbstractEnvironment#getActiveProfiles⽅法获取激活的Profile添加到profiles中.
3. 设置AbstractEnvironment的activeProfiles。

AbstractEnvironment#getActiveProfiles代码如下:

public String[] getActiveProfiles() {
    return StringUtils.toStringArray(doGetActiveProfiles());
}

调⽤了doGetActiveProfiles⽅法.代码如下:

protected Set<String> doGetActiveProfiles() {
        synchronized(this.activeProfiles) {
            if (this.activeProfiles.isEmpty()) {
                String profiles = this.getProperty("spring.profiles.active");
                if (StringUtils.hasText(profiles)) {
                    this.setActiveProfiles(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(profiles)));
                }
            }

            return this.activeProfiles;
        }
    }

⾸先判断activeProfiles是否为空,如果不为空的话,就直接返回.否则调⽤PropertySourcesPropertyResolver#getProperty("spring.profiles.active") 进⾏查找.如果有配置的话,就加⼊到AbstractEnvironment的activeProfiles中

思考 为什么要这么做?
spring boot 有⼀个参数优先级的概念.外置的配置优先于代码级别的.这⾥就是⼀个实现

 5. 通知所有的观察者,发送ApplicationEnvironmentPreparedEvent事件.调⽤的是SpringApplicationRunListeners#environmentPrepared⽅法.关于这⾥上篇⽂章有解释到.最终会调⽤
EventPublishingRunListener#environmentPrepared 发送ApplicationEnvironmentPreparedEvent事件.

对ApplicationEnvironmentPreparedEvent事件感兴趣的有:

org.springframework.boot.context.config.ConfigFileApplicationListener,
org.springframework.boot.context.config.AnsiOutputApplicationListener,
org.springframework.boot.logging.LoggingApplicationListener,
org.springframework.boot.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.autoconfigure.BackgroundPreinitializer,
org.springframework.boot.context.config.DelegatingApplicationListener,
org.springframework.boot.context.FileEncodingApplicationListener

 ConfigFileApplicationListener#onApplicationEvent代码如下:

public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ApplicationEnvironmentPreparedEvent) {
        onApplicationEnvironmentPreparedEvent(
        (ApplicationEnvironmentPreparedEvent) event);
    }
    if (event instanceof ApplicationPreparedEvent) {
        onApplicationPreparedEvent(event);
    }
}

调⽤onApplicationEnvironmentPreparedEvent⽅法.代码如下:
 

rivate void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
        postProcessors.add(this);
        AnnotationAwareOrderComparator.sort(postProcessors);
        Iterator var3 = postProcessors.iterator();

        while(var3.hasNext()) {
            EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
            postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
        }

    }

    List<EnvironmentPostProcessor> loadPostProcessors() {
        return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, this.getClass().getClassLoader());
    }

实现逻辑如下:
⾸先调⽤SpringFactoriesLoader加载EnvironmentPostProcessor.同时也将⾃⼰加⼊到postProcessors.
排序后依次调⽤其postProcessEnvironment⽅法。


对于当前场景来说. EnvironmentPostProcessor如下:

org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,
org.springframework.boot.context.config.ConfigFileApplicationListener

在spring-boot/META-INF/spring.factories中的配置如下:

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor

SpringApplicationJsonEnvironmentPostProcessor#postProcessEnvironment代码如下:
 

 public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        String json = environment.resolvePlaceholders("${spring.application.json:${SPRING_APPLICATION_JSON:}}");
        if (StringUtils.hasText(json)) {
            this.processJson(environment, json);
        }

    }
private void processJson(ConfigurableEnvironment environment, String json) {
        try {
            JsonParser parser = JsonParserFactory.getJsonParser();
            Map<String, Object> map = parser.parseMap(json);
            if (!map.isEmpty()) {
                this.addJsonPropertySource(environment, new MapPropertySource("spring.application.json", this.flatten(map)));
            }
        } catch (Exception var5) {
            logger.warn("Cannot parse JSON for spring.application.json: " + json, var5);
        }

    }

 实现逻辑如下:
1. 依次获取spring.application.json,SPRINGAPPLICATIONJSON的值,如果没有配置的话,默认返回的空字符串。
2. 如果有配置的话,就调⽤processJson⽅法,在environment中添加MapPropertySource.name为spring.application.json。

 

CloudFoundryVcapEnvironmentPostProcessor#postProcessEnvironment代码如下:
 

 public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {
            Properties properties = new Properties();
            this.addWithPrefix(properties, this.getPropertiesFromApplication(environment), "vcap.application.");
            this.addWithPrefix(properties, this.getPropertiesFromServices(environment), "vcap.services.");
            MutablePropertySources propertySources = environment.getPropertySources();
            if (propertySources.contains("commandLineArgs")) {
                propertySources.addAfter("commandLineArgs", new PropertiesPropertySource("vcap", properties));
            } else {
                propertySources.addFirst(new PropertiesPropertySource("vcap", properties));
            }
        }

    }

1. ⾸先调⽤CloudPlatform.CLOUDFOUNDRY#isActive进⾏判断是否在CloudFoundry中.判断的逻辑为environment是否有VCAPAPPLICATION或者VCAP_SERVICES的配置 如下:

 public boolean isActive(Environment environment) {
            return environment.containsProperty("VCAP_APPLICATION") || environment.containsProperty("VCAP_SERVICES");
        }

2. 如果是在CloudFoundry的话.则将vcap.application.*, vcap.services.* 的配置加⼊到Properties中. 接
下来判断 environment中是否有commandLineArgs的Sources.如果有的话,则添加到
commandLineArgs中,否则添加名为vcap的PropertiesPropertySource.

⼀般情况下 CloudPlatform.CLOUD_FOUNDRY 返回的false.

 

ConfigFileApplicationListener#postProcessEnvironment代码如下:

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        this.addPropertySources(environment, application.getResourceLoader());
        this.configureIgnoreBeanInfo(environment);
        this.bindToSpringApplication(environment, application);
    }

addPropertySources⽅法如下:

protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        RandomValuePropertySource.addToEnvironment(environment);
        (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
    }

做了两件事:
1. 调⽤了RandomValuePropertySource#addToEnvironment⽅法,向environment中名为
systemEnvironment的添加了RandomValuePropertySource(名称为random)

代码如下:

/** System environment property source name: {@value} */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
public static final String RANDOM_PROPERTY_SOURCE_NAME = "random";

public static void addToEnvironment(ConfigurableEnvironment environment) {
    environment.getPropertySources().addAfter(
        StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
    new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));
    logger.trace("RandomValuePropertySource add to Environment");
}

正是因此我们才能在配置⽂件中使⽤${random.int} ⽣成随机值.


2. 初始化了Loader并调⽤其load⽅法.代码如下:
 

public void load() {
            this.propertiesLoader = new PropertySourcesLoader();
            this.activatedProfiles = false;
            this.profiles = Collections.asLifoQueue(new LinkedList());
            this.processedProfiles = new LinkedList();
            Set<ConfigFileApplicationListener.Profile> initialActiveProfiles = this.initializeActiveProfiles();
            this.profiles.addAll(this.getUnprocessedActiveProfiles(initialActiveProfiles));
            if (this.profiles.isEmpty()) {
                String[] var2 = this.environment.getDefaultProfiles();
                int var3 = var2.length;

                for(int var4 = 0; var4 < var3; ++var4) {
                    String defaultProfileName = var2[var4];
                    ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(defaultProfileName, true);
                    if (!this.profiles.contains(defaultProfile)) {
                        this.profiles.add(defaultProfile);
                    }
                }
            }

            this.profiles.add((Object)null);

            ConfigFileApplicationListener.Profile profile;
            label41:
            for(; !this.profiles.isEmpty(); this.processedProfiles.add(profile)) {
                profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
                Iterator var8 = this.getSearchLocations().iterator();

                while(true) {
                    while(true) {
                        if (!var8.hasNext()) {
                            continue label41;
                        }

                        String location = (String)var8.next();
                        if (!location.endsWith("/")) {
                            this.load(location, (String)null, profile);
                        } else {
                            Iterator var10 = this.getSearchNames().iterator();

                            while(var10.hasNext()) {
                                String name = (String)var10.next();
                                this.load(location, name, profile);
                            }
                        }
                    }
                }
            }

            this.addConfigurationProperties(this.propertiesLoader.getPropertySources());
        }

处理步骤如下:
1. 调⽤initializeActiveProfiles.获得ActiveProfiles.将未激活的Profiles加⼊到profiles中.如果
profiles为空的话,就将spring.profiles.default配置的profile添加到profiles中.
2. 依次遍历profiles中的profile.依次在classpath:/,classpath:/config/,file:./,file:./config/中加载
application的配置.调⽤ConfigFileApplicationListener$Loader#load进⾏加载.
3. 调⽤addConfigurationProperties,向environment中添加ConfigurationPropertySources.代码如
下:
 

private void addConfigurationProperties(MutablePropertySources sources) {
            List<PropertySource<?>> reorderedSources = new ArrayList();
            Iterator var3 = sources.iterator();

            while(var3.hasNext()) {
                PropertySource<?> item = (PropertySource)var3.next();
                reorderedSources.add(item);
            }

            this.addConfigurationProperties(new ConfigFileApplicationListener.ConfigurationPropertySources(reorderedSources));
        }

initializeActiveProfiles代码如下:

private Set<Profile> initializeActiveProfiles() {
    // 1. 如果environment不含有spring.profiles.active和spring.profiles.inclu
    de的配置话,返回空集合
    if (!this.environment.containsProperty(ACTIVE_PROFILES_PROPERTY)
        && !this.environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) {
        return Collections.emptySet();
    }
    // Any pre-existing active profiles set via property sources (e.g. System
    // properties) take precedence over those added in config files.
    // 2. 调⽤bindSpringProfiles,⽣成SpringProfiles
    SpringProfiles springProfiles = bindSpringProfiles(
    this.environment.getPropertySources());
    Set<Profile> activeProfiles = new LinkedHashSet<Profile>(
        springProfiles.getActiveProfiles());
    activeProfiles.addAll(springProfiles.getIncludeProfiles());
    // 3. 调⽤maybeActivateProfiles.将activatedProfiles设为true
    maybeActivateProfiles(activeProfiles);
    return activeProfiles;
}

代码的逻辑如下:
1. 如果environment不含有spring.profiles.active和spring.profiles.include的配置话,返回空集合

注意: 当前的environment拥有的source有 commandLineArgs、servletConfigInitParams、 servletContextInitParams、 systemProperties、systemEnvironment, RandomValuePropertySource 如果想 不返回空的话,就需要在以上的source中有配置.最简单的⽅式是通过命令⾏的⽅式传⼊ --spring.profiles.active=youprofiles 即可

2. 调⽤bindSpringProfiles,⽣成SpringProfiles
3. 调⽤maybeActivateProfiles.将activatedProfiles设为true


 bindSpringProfiles代码如下:

private SpringProfiles bindSpringProfiles(PropertySources propertySources){
    SpringProfiles springProfiles = new SpringProfiles();
    RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles,
        "spring.profiles");
    dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
    springProfiles.setActive(resolvePlaceholders(springProfiles.getActive(
        )));
    springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));
    return springProfiles;
}

 逻辑如下:
1. 初始化SpringProfiles和RelaxedDataBinder.RelaxedDataBinder读取的配置是前缀为spring.profiles的配置.
2. 实例化PropertySourcesPropertyValues,调⽤DataBinder#bind进⾏数据的绑定.
3. 设置SpringProfiles的Active和Include属性.
其中第2步中PropertySourcesPropertyValues的构造器代码如下:

PropertySourcesPropertyValues(PropertySources propertySources,
Collection<String> nonEnumerableFallbackNames,PropertyNamePatternsMatcher includes, boolean resolvePlaceholders) {
    Assert.notNull(propertySources, "PropertySources must not be null");
    Assert.notNull(includes, "Includes must not be null");
    this.propertySources = propertySources;
    this.nonEnumerableFallbackNames = nonEnumerableFallbackNames;
    this.includes = includes;
    this.resolvePlaceholders = resolvePlaceholders;
    PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
        propertySources);
    for (PropertySource<?> source : propertySources) {
        processPropertySource(source, resolver);
    }
 }

其中最主要的代码是 初始化了 PropertySourcesPropertyResolver.并依次遍历environment中的
PropertySources.调⽤processPropertySource⽅法进⾏处理.
 

注意
这⾥的source为 [SimpleCommandLinePropertySource {name='commandLineArgs'},StubPropertySource {name='servletConfigInitParams'}, StubPropertySource{name='servletContextInitParams'}, MapPropertySource {name='systemProperties'},SystemEnvironmentPropertySource {name='systemEnvironment'},RandomValuePropertySource {name='random'}}

 processPropertySource 代码如下:

private void processPropertySource(PropertySource<?> source,
    PropertySourcesPropertyResolver resolver) {
    if (source instanceof CompositePropertySource) {
        processCompositePropertySource((CompositePropertySource) source, resolver);
    }else if (source instanceof EnumerablePropertySource) {
        processEnumerablePropertySource((EnumerablePropertySource<?>) source,resolver, this.includes);
    }else {
    processNonEnumerablePropertySource(source, resolver);
    }
}

这⾥的逻辑很简单:
1. 如果 source 为 CompositePropertySource的话,调⽤processCompositePropertySource
2. 如果 source 为 EnumerablePropertySource 的话,调⽤processEnumerablePropertySource
3. 否则 调⽤ processNonEnumerablePropertySource
这⾥我们需要看下各个source的类图.分别如下:

 StubPropertySource 类图为:

MapPropertySource 类图为:
 

 SystemEnvironmentPropertySource 类图为:

 

 RandomValuePropertySource 类图为:

(未完结,暂搁置)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值