容器的运行环境包含了应用配置和环境相关信息,后面所有关于配置和环境的操作都基于此类。构建容器环境实现代码如下:
/**
* 构建容器环境
* @param listeners 监听器
* @param applicationArguments 命令行参数
* @return 构建的环境对象
*/
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 第一步:创建Environment实例
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 第二步:配置Environment
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 第三步:监听回调
listeners.environmentPrepared(environment);
// 第四步:绑定到SpringApplication
bindToSpringApplication(environment);
//这一步是非SpringMVC项目的处理,暂时忽略
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 绑定ConfigurationPropertySourcesPropertySource到ConfigurableEnvironment中,name为configurationProperties,实例是SpringConfigurationPropertySources,属性实际是ConfigurableEnvironment中的MutablePropertySources
ConfigurationPropertySources.attach(environment);
return environment;
}
从代码中可以看到,构建容器环境主要包含四个步骤:
- 创建Environment实例
- 配置Environment
- 监听回调
- 绑定到SpringApplication
第一步:创建Environment实例
根据Web应用类型不同,Spring Boot提供了三种容器环境,如果是SERVLET应用,则使用StandardServletEnvironment,如果是REACTIVE应用,则使用StandardReactiveWebEnvironment,其他情况都使用StandardEnvironment。
StandardServletEnvironment和StandardReactiveWebEnvironment都继承自StandardEnvironment,不同之处在于,StandardServletEnvironment增加了加载和解析web.xml配置的逻辑。
具体代码如下:
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
第二步:配置Environment
Environment是当前应用运行环境的公开接口,主要包括应用程序运行环境的两个关键方面:配置文件(profiles)和属性。Environment继承自接口PropertyResolver,而PropertyResolver提供了属性访问的相关方法。
配置Environment包含两部分:
- 配置Properties
// Environment继承关系
在构建StandardEnvironment对象时,会调用System.getProperty()和System.getEnv()方法,这两个方法分别用于加载系统配置和系统环境变量。详情参考:系统变量之System.getEnv()和System.getProperty()
如果需要将命令行参数存入Environment配置中,则会解析命令行参数为KV形式,并保存到Environment配置中。 - 配置Profiles
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<>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
第三步:监听回调
在这个过程中,会遍历所有在spring.factories文件中配置的SpringApplicationRunListeners实例,并调用其environmentPrepared方法。
配置文件的加载就是在监听器的回调方法中完成的。
第四步:绑定到SpringApplication
在这个过程中,会将刚才构建好的Environment对象绑定到当前的SpringApplication中。
网友评论