springboot源码分析系列文章
springboot启动流程源码之一(new SpringApplication(primarySources))
springboot启动流程源码分析(二)run(args)
springboot启动流程源码分析(三)getRunListeners()
源码解析
prepareEnvironment按字面意思就是准备环境,那到底准备什么环境呢?我们一起来慢慢看,其源代码如下
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
//创建并配置相应的环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
//根据用户配置,配置 environment系统环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// 启动相应的监听器,其中一个重要的监听器 ConfigFileApplicationListener 就是加载项目配置文件的监听器
listeners.environmentPrepared(environment);
//bindToSpringApplication绑定环境
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
//环境转换
//如果environment.class和模块使用的EnvironmentClass()不一致
//那么转换成一样的
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
//将环境依附到PropertySources
ConfigurationPropertySources.attach(environment);
return environment;
}
①getOrCreateEnvironment()
// 获取或创建Environment,很显然我们这里是创建StandardServletEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
// 存在则直接返回
if (this.environment != null) {
return this.environment;
}
// 根据webApplicationType创建对应的Environment
switch (this.webApplicationType) {
case SERVLET:
// 标准的Servlet环境,也就是我们说的web环境
return new StandardServletEnvironment();
case REACTIVE:
//REACTIVE环境
return new StandardReactiveWebEnvironment();
default:
// 标准环境,非web环境
return new StandardEnvironment();
}
}
②configureEnvironment(environment,applicationArguments.getSourceArgs());
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
//增加类型转换服务-默认为true
if (this.addConversionService) {
//返回ApplicationConversionService实例
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
//设置类型转换服务
environment.setConversionService((ConfigurableConversionService) conversionService);
}
//加载配置源 及 命令行属性
configurePropertySources(environment, args);
//配置当前active的描述文件
configureProfiles(environment, args);
}
a.configurePropertySources(environment, args);
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
//调用AbstractEnvironment的getPropertySources()方法
//获取之前配置的所有属性
MutablePropertySources sources = environment.getPropertySources();
//如果this.defaultProperties不为null
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
//那么添加defaultProperties到propertySources的末尾
sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
}
//这里addCommandLineProperties默认为true 如果有命令行参数的数
if (this.addCommandLineProperties && args.length > 0) {
//name为:commandLineArgs
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
//如果之前的MutablePropertySources中有name为commandLineArgs的PropertySource的话,则把当前命令行参数转换为CompositePropertySource类型,和原来的PropertySource进行合并,替换原来的PropertySource
if (sources.contains(name)) {
//如果sources中包含了"commandLineArgs",
//那么将其替换为"springApplicationCommandLineArgs"
PropertySource<?> source = sources.get(name);
//先将"commandLineArgs"修改为null,
CompositePropertySource composite = new CompositePropertySource(name);
//然后新增一个PropertySource
//name为"springApplicationCommandLineArgs",
//source不变
composite.addPropertySource(
new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
//替换
sources.replace(name, composite);
}
else {
//如果之前没有name为commandLineArgs的PropertySource的话,则将其添加为MutablePropertySources中的第一个元素,注意了这里讲命令行参数添加为ConfigurableEnvironment中MutablePropertySources实例的第一个元素,且永远是第一个元素
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
b.configureProfiles(environment, args);
//传入参数为StandardServletEnvironment和命令行参数
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
//调用的是AbstractEnvironment的getActiveProfiles()方法
Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
//再次获取和配置profile
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
//设置environment的profile
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
③ConfigurationPropertySources.attach(environment);
//如果配置了configurationProperties属性, 那么将其放在environment的propertySources的首部
public static void attach(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
//取得environment中的propertySources
MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
PropertySource<?> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME);
if (attached != null && attached.getSource() != sources) {
//如果存在的话,直接移除
sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
attached = null;
}
if (attached == null) {
//将propertySources转换为SpringConfigurationPropertySources,放在首位
sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
new SpringConfigurationPropertySources(sources)));
}
}
④listeners.environmentPrepared(environment);
关于multicastEvent方法,详见springboot启动流程源码分析(三)getRunListeners()中详解。
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
⑤bindToSpringApplication(environment);
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
try {
//如果指定了main函数,那么会将当前环境绑定到指定的SpringApplication中
Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
}
catch (Exception ex) {
throw new IllegalStateException("Cannot bind to SpringApplication", ex);
}
}
⑥convertEnvironmentIfNecessary(environment,deduceEnvironmentClass())
//环境转换
StandardEnvironment convertEnvironmentIfNecessary(ConfigurableEnvironment environment,
Class<? extends StandardEnvironment> type) {
if (type.equals(environment.getClass())) {
return (StandardEnvironment) environment;
}
//environment.getClass()不是StandardEnvironment的实例
return convertEnvironment(environment, type);
}
//环境转换
private StandardEnvironment convertEnvironment(ConfigurableEnvironment environment,
Class<? extends StandardEnvironment> type) {
//新建一个StandardEnvironment实例
//然后赋值
StandardEnvironment result = createEnvironment(type);
result.setActiveProfiles(environment.getActiveProfiles());
result.setConversionService(environment.getConversionService());
copyPropertySources(environment, result);
return result;
}
关注公众号
每周会更新干货知识