最近很多篇都是围绕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;}}
我们创建的时候就是根据应用类型创建的&#xff0c;也没修改过&#xff0c;所以convertEnvironmentIfNecessary方法中判断类型是一致的&#xff0c;不需要做转型
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 &#61; ((ConfigurableEnvironment)environment).getPropertySources();PropertySource<?> attached &#61; sources.get("configurationProperties");if (attached !&#61; null && attached.getSource() !&#61; sources) {sources.remove("configurationProperties");attached &#61; null;}if (attached &#61;&#61; null) {sources.addFirst(new ConfigurationPropertySourcesPropertySource("configurationProperties", new SpringConfigurationPropertySources(sources)));}}
它先从environment中取出了所有的PropertySource&#xff0c;然后用这些配置构造了一个名为configurationProperties的配置项&#xff0c;添加到PropertySource列表的最前面&#xff0c;也就是赋予了最高的优先级
其具体类型为ConfigurationPropertySourcesPropertySource
class ConfigurationPropertySourcesPropertySource extends PropertySource<Iterable<ConfigurationPropertySource>> implements OriginLookup<String> {
从泛型参数可知&#xff0c;它存储的是一个PropertySource列表的迭代器&#xff0c;也就是说这个新的PropertySource持有了所有environment中其它PropertySource的引用&#xff0c;本身并没有额外的信息&#xff0c;如果将来有其它组件需要使用配置信息&#xff0c;那么只需要将它暴露出去就行了&#xff0c;屏蔽了底层不同PropertySource的细节
至此run方法里的这行prepareEnvironment方法就结束了&#xff0c;终于可以回到run方法的主干了…