SpringBoot运行流程,首先从 Spring Application调用 run 方法开始,如下所示:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
在main主方法中:调用了SpringApplication的run方法,该方法完成了整个SpringBoot的启动流程。
下面让我们一起来看一下这个方法执行过程中都做了哪些工作:
//SpringApplication的run方法 public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
由上面的代码可以指定,run方法在SpringApplication是一个静态方法,该方法会将传入的启动类(Application.class)作为SpringApplication的构造参数来创建一个SpringApplication的实例。
下面我们看一下run方法的代码实现:
//SpringApplication的run方法 public ConfigurableApplicationContext run(String... args) { //创建StopWatch对象用于统计run方法的执行耗时 StopWatch stopWatch = new StopWatch(); //调用start方法表示开始启动计时 stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); //通过SPI机制加载所有的SpringApplicatoinRunListener监听器 //SpringBoot启动过程的不同阶段会回调该监听器的不同方法 SpringApplicationRunListeners listeners = getRunListeners(args); //调用SpringApplicatoinRunListener的starting方法 listeners.starting(); try { //将SpringApplication的启动参数封装为ApplicationArguments ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //创建SpringBoot应用使用的环境变量对象,内部会根据webApplicationType创建不同的环境对象, //这里会创建StandardServletEnvironment对象 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //打印banner,默认是在管控台打印SpringBoot Banner printedBanner = printBanner(environment); //创建使用的ApplicationContext上下文对象,这里会根据webApplicationType创建不同的对象上下文对象 //这里创建的是AnnotationConfigServletWebServerApplicationContext对象 context = createApplicationContext(); //通过SPI机制加载SpringBoot的异常报告对象SpringBootExceptionReporter //当SpringBoot启动过程中抛出异常时,会通过该对象打印错误日志 exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //ApplicationContext上下文对象创建完毕后,会调用prepareContext为ApplicationContext做一些准备工作 //比如为ApplicationContext设置环境变量,回调ApplicationContextInitializer对象的initialize方法等 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //调用ApplicationContext的refresh方法,启动整个Spring应用程序 refreshContext(context); //停止StopWatch计时器 stopWatch.stop(); //调用SpringApplcationListener对象的started监听方法 listeners.started(context); //回调Spring中的的ApplicationRunner对象和CommandLineRunner对象 callRunners(context, applicationArguments); } catch (Throwable ex) { //抛出异常,则使用SpringExceptionReporter打印异常报告 handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //启动成功,则调用SpringApplicationListener对象的running监听方法 listeners.running(context); } catch (Throwable ex) { //抛出异常,则使用SpringExceptionReporter打印异常报告 handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } //返回创建的ApplicationContext应用上下文 return context; }
SpringBoot运行流程,大致分为如下11大执行流程步骤:
1)创建 Spring Application 实例,调用 run 方法,同时将启动入口类作 为参数传递进去;
2)通过 Spring Factories Loader 加载 META-INF/spring.factories 文 件;
3)然后由 SpringApplicationRunListener 来发出 starting 消息;
4)创建参数,并配置当前 SpringBoot 应用需要使用的 Environment 实 例;
5)完成之后,依然由 SpringApplicationRunListener 来发出 environmentPrepared 消息;
6)创建 Spring 的应用上下文实例:ApplicationContext,初始化该实例 并设置应用环境配置实例:Environment,同时加载相关的配置项;
7)由 SpringApplicationRunListener 发出 contextPrepared 消息,告 知 SpringBoot 应用当前使用的 ApplicationContext 已准备完毕;
8)将各种 Bean 组件装载入 Spring 的 IO 容器/应用上下文: ApplicationContext 中,继续由 SpringApplicationRunListener 来发出 contextLoaded 消息,告知 SpringBoot 应用当前使用的 ApplicationContext 已准备完毕;
9)重新刷新 Refresh Spring 的应用上下文实例:ApplicationContext, 完成 IOC 容器可用的最后一步;
10)由 SpringApplicationRunListener 发出 started 消息,完成最终的 程序的启动;
11)由 SpringApplicationRunListener 发出 running 消息,告知程序已 成功运行起来了。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》