SpringBoot启动流程源码分析( 四 )

starting方法
这个starting方法实际上就是通过事件广播发布了一个应用启动事件
private final SimpleApplicationEventMulticaster initialMulticaster;public void starting() {this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));}复制
准备启动环境然后我们再回过去看SpringApplication#prepareEnvironment方法 , 这个方法是准备启动环境的意思
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {// 获取或者创建一个配置环境ConfigurableEnvironment environment = this.getOrCreateEnvironment();// 配置环境this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());// 通过启动类应用监听器发布环境准备事件listeners.environmentPrepared((ConfigurableEnvironment)environment);// 将配置环境绑定到SpringApplicationthis.bindToSpringApplication((ConfigurableEnvironment)environment);if (!this.isCustomEnvironment) {// 如果是非自定义环境则根据需要转换成推断出的Web环境environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());}// 通过环境变量添加属性配置源ConfigurationPropertySources.attach((Environment)environment);// 返回经过处理的配置环境return (ConfigurableEnvironment)environment;}复制
getOrCreateEnvironment方法private ConfigurableEnvironment environment;private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {// this.environment不为空则直接返回return this.environment;} else {switch(this.webApplicationType) {// 根据web应用类型创建环境case SERVLET:// servlet web应用返回标准StandardServletEnvironment实例return new StandardServletEnvironment();case REACTIVE:// reactive web应用环境返回StandardReactiveWebEnvironment实例return new StandardReactiveWebEnvironment();default:// 默认返回非web应用的StandardEnvironment实例return new StandardEnvironment();}}}复制
前面的WebApplicationType#deduceFromClasspath方法码分析中我们知道返回的是一个SERVLET枚举 。因此 , spring-boot项目中具有spring-boot-starter-web起步依赖时getOrCreateEnvironment方法返回的是一个StandardServletEnvironment实例
SpringApplicationRunListeners#environmentPrepared接下来我们进入SpringApplicationRunListeners#environmentPrepared方法
public void environmentPrepared(ConfigurableEnvironment environment) {Iterator var2 = this.listeners.iterator();while(var2.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();// 通过迭代遍历启动监听器发布环境准备事件listener.environmentPrepared(environment);}}复制
SpringApplication#bindToSpringApplication方法准备好环境后进入SpringApplication#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#get方法public static Binder get(Environment environment) {// 这里传入了一个属性源占位符解析器类实例参数return new Binder(ConfigurationPropertySources.get(environment), new PropertySourcesPlaceholdersResolver(environment));}复制
Binder类构造方法【SpringBoot启动流程源码分析】public Binder(Iterable<ConfigurationPropertySource> sources, PlaceholdersResolver placeholdersResolver) {this(sources, placeholdersResolver, (ConversionService)null, (Consumer)null);}public Binder(Iterable<ConfigurationPropertySource> sources, PlaceholdersResolver placeholdersResolver, ConversionService conversionService, Consumer<PropertyEditorRegistry> propertyEditorInitializer) {Assert.notNull(sources, "Sources must not be null");this.sources = sources;this.placeholdersResolver = placeholdersResolver != null ? placeholdersResolver : PlaceholdersResolver.NONE;this.conversionService = conversionService != null ? conversionService : ApplicationConversionService.getSharedInstance();this.propertyEditorInitializer = propertyEditorInitializer;}

经验总结扩展阅读