介绍
前面介绍了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。