SpringBoot源码(六): 创建ConfigurableEnvironment

介绍

前面介绍了spring对于键值的抽象PropertySource,以及对外提供数据的统一处理接口PropertyResolver。还有对ConfigurableEnvironment的源码解析。接下来继续看springBoot启动流程的源码prepareEnvironment。

 

prepareEnvironment

	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// 创建environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
        // 配置environment
		configureEnvironment(environment, applicationArguments.getSourceArgs());
        // 发送广播
		listeners.environmentPrepared(environment);
        // 将配置绑定在springApplication上
		bindToSpringApplication(environment);
		if (this.webApplicationType == WebApplicationType.NONE) {
            // 新创建变量
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
        // 附加额外信息
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

这节说下创建environment和配置environment。对于广播那块非常重要的ConfigFileApplicationListener的内容,下一节会专门说到。

 

getOrCreateEnvironment

	private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		if (this.webApplicationType == WebApplicationType.SERVLET) {
			return new StandardServletEnvironment();
		}
		return new StandardEnvironment();
	}

根据webApplicationType来创建不同的environment,在SpringApplication执行run方法之前会初始化,初始化时候就会执行deduceWebApplicationType判断webApplicationType。在第一章时候就说过了。这边就根据类型来创建environment。

 

configureEnvironment

	protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
        // 配置PropertySources
		configurePropertySources(environment, args);
        // 配置Profiles
		configureProfiles(environment, args);
	}

	protected void configurePropertySources(ConfigurableEnvironment environment,
			String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(
					new MapPropertySource("defaultProperties", this.defaultProperties));
		}
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
            // 如果有命令行参数,就解析arg参数,加上之前的source放到CompositePropertySource中
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(new SimpleCommandLinePropertySource(
						"springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
                // 解析arg参数放到MutablePropertySources中
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

	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 *)
		Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(StringUtils.toStringArray(profiles));
	}

configureEnvironment主要有两个方法:configurePropertySources和configureProfiles。

 

configurePropertySources

configurePropertySources主要是去解析参数args参数和命令参数放到MutablePropertySources中。之前说过对于参数以及配置文件的解析,都会转化成PropertySource类型,存到MutablePropertySources中去。这边对于命令行参数的解析就是转化成了SimpleCommandLinePropertySource的格式。

大家有没有觉得SimpleCommandLinePropertySource这个类很熟悉,对的。之前在第三章中ApplicationArguments类中Source就是继承这个类型。并且对于参数的解析之前也说过,这边不再赘述。

这里就是把参数解析成SimpleCommandLinePropertySource加到MutablePropertySources中去,并且放在第一的位置。

 

configureProfiles

configureProfiles主要就是environment.getActiveProfiles(),我们看下代码:

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

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

可以看到,主要就是从getProperty方法获取profiles,也就是从MutablePropertySources中获取profiles。

此时如果有 spring.profiles.active参数这边就会取到profiles,否则就没有。

所以我们经常会在命令行参数中设置 --spring.profiles.active=dev这样的设置,由于configurePropertySources会解析命令行参数,这样就会取到了spring.profiles.active的参数了。

然后configureProfiles就设置setActiveProfiles了。

这样environment的创建和配置就完成了。

 

总结

这节简单介绍了environment的创建和获取,都比较简单。下一节介绍非常重要的配置文件的解析,ConfigFileApplicationListener。

上一篇:【Azure Developer】Github Action部署资源(ARM模板)到Azure中国区时,遇见登录问题的解决办法


下一篇:SpringBoot外部化配置