SpringBoot启动流程原理解析(二)

在上一章我们分析了SpingBoot启动流程中实例化SpingApplication的过程。

return new SpringApplication(primarySources).run(args);
这篇文章咱么说下run()方法开始之后都做了那些事情。

继续往下跟着源码进入到run()这个是比较核心的一个方法了

SpringBoot启动流程原理解析(二)

public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); // 计时器开始 stopWatch.start(); // 创建启动上下文对象 DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; // 配置Handless模式,是在缺少显示屏、键盘或鼠标时的系统配置 // 默认为true configureHeadlessProperty(); //获取并启动监听器 SpringApplicationRunListeners listeners = getRunListeners(args); // 启动监听器 listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); // 忽略配置的bean configureIgnoreBeanInfo(environment); // 打印banner,就是启动的时候在控制台的spring图案 Banner printedBanner = printBanner(environment); // 创建容器 context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 准备应用上下文(spring容器前置处理) prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 刷新容器 refreshContext(context); // 刷新容器后的扩展接口(spring容器后置处理) afterRefresh(context, applicationArguments); // 结束计时器并打印,这就是我们启动后console的显示的时间 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 发布监听应用上下文启动完成(发出启动结束事件) listeners.started(context); // 执行runner callRunners(context, applicationArguments); } catch (Throwable ex) { // 异常处理,如果run过程发生异常 handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { // 监听应用上下文运行中 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } // 返回最终构建的容器对象 return context; }

接下来就对上面的关键步骤一一解释

1. 获取所有的监听器

SpringBoot启动流程原理解析(二)


这段代码我们比较熟悉了,上一篇咱么详细介绍过,它的主要作用就是去META-INFO/spring.factories 中加载配置SpringApplicationRunListener的监听器如下

SpringBoot启动流程原理解析(二)


显然只有一个事件发布监听器类,拿到了EventPublishingRunListener启动事件发布监听器,下一步就是开始启动了listeners.starting();我们往下跟源码看

@Override public void starting(ConfigurableBootstrapContext bootstrapContext) { this.initialMulticaster .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args)); }

启动的时候实际上是又创建了一个ApplicationStartingEvent对象,其实就是监听应用启动事件。
其中 initialMulticaster是一个SimpleApplicationEventMuticaster

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); // 获取线程池,为每个监听事件创建一个线程 Executor executor = this.getTaskExecutor(); // 根据ApplicationStartingEvent事件类型找到对应的监听器,并迭代 Iterator var5 = this.getApplicationListeners(event, type).iterator(); while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { // executor.execute(() -> { this.invokeListener(listener, event); }); } else { this.invokeListener(listener, event); } } } 2.准备环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment // 这里我们加入了web依赖所以是一个servlet容器 ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置环境 configureEnvironment(environment, applicationArguments.getSourceArgs()); // 环境准备完成 ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); configureAdditionalProfiles(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzyjd.html