最近很多篇都是围绕prepareEnvironment方法在分析,上篇补充了ApplicationEnvironmentPreparedEvent事件的处理,相当于下面的listeners.environmentPrepared方法就分析完了,本文就把这个方法中剩下的几行代码收下尾
先看第一行bindToSpringApplication
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
try {
Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
} catch (Exception var3) {
throw new IllegalStateException("Cannot bind to SpringApplication", var3);
}
}
Binder是SpringBoot 2.X引入的新特性,用于将environment的属性绑定到目标类上
这里就相当于将spring.main开头的属性,绑定到SpringApplicaiton对象上,前提是SpringApplication提供了相应属性的set方法
比如常见的配置spring.main.allow-bean-definition-overriding=true,SpringApplication类存在该属性,且有对应的set方法,那么就会将配置文件中的值赋给该属性
public class SpringApplication {
......
private boolean allowBeanDefinitionOverriding;
......
......
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
}
......
继续下一行
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
isCustomEnvironment属性在SpringApplication的构造函数中初始化为false,所以会进if,它的作用就是对environment的类型做个校正
deduceEnvironmentClass方法根据应用类型推断environment应该是哪个实现类
private Class<? extends StandardEnvironment> deduceEnvironmentClass() {
switch(this.webApplicationType) {
case SERVLET:
return StandardServletEnvironment.class;
case REACTIVE:
return StandardReactiveWebEnvironment.class;
default:
return StandardEnvironment.class;
}
}
我们创建的时候就是根据应用类型创建的,也没修改过,所以convertEnvironmentIfNecessary方法中判断类型是一致的,不需要做转型
StandardEnvironment convertEnvironmentIfNecessary(ConfigurableEnvironment environment, Class<? extends StandardEnvironment> type) {
return type.equals(environment.getClass()) ? (StandardEnvironment)environment : this.convertEnvironment(environment, type);
}
最后一行ConfigurationPropertySources.attach方法
public static void attach(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
MutablePropertySources sources = ((ConfigurableEnvironment)environment).getPropertySources();
PropertySource<?> attached = sources.get("configurationProperties");
if (attached != null && attached.getSource() != sources) {
sources.remove("configurationProperties");
attached = null;
}
if (attached == null) {
sources.addFirst(new ConfigurationPropertySourcesPropertySource("configurationProperties", new SpringConfigurationPropertySources(sources)));
}
}
它先从environment中取出了所有的PropertySource,然后用这些配置构造了一个名为configurationProperties的配置项,添加到PropertySource列表的最前面,也就是赋予了最高的优先级
其具体类型为ConfigurationPropertySourcesPropertySource
class ConfigurationPropertySourcesPropertySource extends PropertySource<Iterable<ConfigurationPropertySource>> implements OriginLookup<String> {
从泛型参数可知,它存储的是一个PropertySource列表的迭代器,也就是说这个新的PropertySource持有了所有environment中其它PropertySource的引用,本身并没有额外的信息,如果将来有其它组件需要使用配置信息,那么只需要将它暴露出去就行了,屏蔽了底层不同PropertySource的细节
至此run方法里的这行prepareEnvironment方法就结束了,终于可以回到run方法的主干了…