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

main方法,若是则返回通过反射加载全类名后的主启动类;若是运行时异常堆栈元素中不存在main方法 , 则返回空 。SpringApplication类实例化后就会调用run方法,下面我们再回到SpringApplication类非静态的run方法源码
SpringApplication类实例run方法public ConfigurableApplicationContext run(String... args) {// new了一个 StopWatch并启动了它StopWatch stopWatch = new StopWatch();stopWatch.start();// springboot启动时使用ConfigurableApplicationContext作为BeanFactory接口的实现类ConfigurableApplicationContext context = null;// 实例化一个异常报告集合Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();// 设置系统属性java.awt.headless,默认为falsethis.configureHeadlessProperty();// 获取所有的启动监听器SpringApplicationRunListeners listeners = this.getRunListeners(args);// 遍历启动类监听器列表,并逐个启动listeners.starting();Collection exceptionReporters;try {// 实例化启动类命令参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备启动环境ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);// 配置环境中可忽略的bean信息this.configureIgnoreBeanInfo(environment);// 打印springboot项目的logo图标Banner printedBanner = this.printBanner(environment);// 创建应用上下文,也就是Spring IOC容器context = this.createApplicationContext();// 收集异常报告集合exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);// 准备应用上下文环境,会去加载配置类基于注解的bean、xml配置文件中定义的beanthis.prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新上下文,对于servlet应用程序这个方法会去创建和启动web服务器this.refreshContext(context);// 这个方法啥也没干this.afterRefresh(context, applicationArguments);// 启动完成,记时停止stopWatch.stop();if (this.logStartupInfo) {// 如果开启了记录启动日志,则记录应用程序启动过程耗时(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}// 应用运行时监听器发布应用启动事件listeners.started(context);// 调用启动类中的任务this.callRunners(context, applicationArguments);} catch (Throwable var10) {// 启动过程发生异常则处理异常,并跑出IllegalStateException类型异常this.handleRunFailure(context, var10, exceptionReporters, listeners);throw new IllegalStateException(var10);}复制
SpringApplicationRunListeners#starting方法public void starting() {Iterator var1 = this.listeners.iterator();while(var1.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();listener.starting();}}复制
通过上面的源码可以看到通过循环遍历启动类监听器集合中的每个启动类监听器,然后调用每个启动类监听器的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();}}}

推荐阅读