Spring Boot的执行流程如下图所示:(图片来源于网络)
上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。在下面的启动程序中我们会串联起结构中的主要功能。下面我们将从入门案例分析Spring Boot相关的原理。
@RestController @SpringBootApplication public class DemoApplication { @RequestMapping("/") String index(){ return "Hello World!"; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
首先,springboot的启动类必须满足以下两个条件:
l 该类必须在项目的根目录或者父包中;
l 该类必须有@SpringBootApplication注释,这个注释说明了该类为springboot程序的启动类,是整个程序的入口;
SpringBoot程序启动时,启动类的main方法是程序的入口,执行
SpringApplication.run(DemoApplication.class, args);
该方法返回一个ConfigurableApplicationContext对象,使用注解的时候返回的具体类型是AnnotationConfigApplicationContext或AnnotationConfigEmbeddedWebApplicationContext,当支持web的时候是第二个。
当程序开始启动时,在启动类中调用SpringApplication的静态run方法,此时会执行以下操作:
1、首先新建一个SpringApplication对象;
2、然后执行对象的run()方法;
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start();//新建一个StopWatch,并启动用于监测程序运行时间 ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting();//获取SpringApplicationRunListeners对象,并启动该监听器 Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 根据启动时传入的参数args,新建ApplicationArguments对象 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); // 新建ConfigurableEnvironment对象,具体类型为StandardServletEnvironment this.configureIgnoreBeanInfo(environment);// 在其创建过程中将会加载springboot的配置文件application.properties,同时将其绑定的SpringApplication程序中 Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext();//创建ConfigurableApplicationContext对象context exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context);// 执行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) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
3、对配置的启动类所在包及子包中的类进行扫描,对于有spring相关注解的类,通过反射为其创建代理对象,并交由spring容器管理。
回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成,接下来下一篇我们来探讨自动化配置是如何实现。