SpringApplication.run()
在上一篇中,我们分析了 SpringBoot 启动过程中的 @SpringBootApplocation ,其主要功能就是加载对应的 @Configuration 及 Auto Configure 模块中的组件信息,并将组件内容加入到容器中。
这篇将开始分析 SpringBoot 的启动过程,而启动过程中最核心的两个部分就是 SpringApplication 的启动过程 及 SpringApplication 的 run 方法 ,下面为分析过程:
SpringApplication 的构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { 	    ... 	    // 设置启动的源Class,即启动的SpringBootLearningApplication.class对象,包含了对应的 classLoader         this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));                  // 设置了 webApplication的类型,尚未配置web,所以当前为 NONE (Servlet, Reactive)         this.webApplicationType = WebApplicationType.deduceFromClasspath();                  // 借助 SpringFactoriesLoader 找到 /META-INF/spring.factories 下的所有配置 key 为 ApplicationContextInitializer            (所有的应用初始化器),实例化并设置到 setInitializers 这个集合属性中         this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));                  // 和上面一样, 通过 SpringFactoriesLoader 找到所有配置 key 为 ApplicationListener (所有的应用程序监听器),             实例化并设置到 setListeners 集合属性中         this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));                 // 找到 StackTrace (方法调用堆栈)中的 main 方法,即入口类的名字,并 Class.forName 得到类对象         this.mainApplicationClass = this.deduceMainApplicationClass();     }
  | 
 
ApplicationEvent
SpringBoot 中使用了很多 Event 去响应容器状态,而 ApplicationEvent 为多个组件 bean 提供了消息通信的支持,其中就包括了接下来在 run( ) 使用到的 SpringApplicationEvent ,它实现了全局的 base ApplicationEvent,并扩展为多个 Spring 启动中的事件 Event,如下:
- ApplicationContextInitializedEvent  
 
- ApplicationEnvironmentPreparedEvent  
 
- ApplicationPreparedEvent
 
- ApplicationStartedEvent
 
- ApplicationReadyEvent
 
- ApplicationFailedEvent
 
- ApplicationStartingEvent
 

事件的传递过程如下:
- SpringApplicationRunListener 调用对应的操作如 ( starting, running, contextLoad… )
 
- SpringApplicationRunListener 内部针对不同的事件,遍历内部集合调用对应的方法,具体实现类为 EventPublishingRunListener 调用
 
- EventPublishingRunListener  将对应的操作 ( starting, environmentPrepared.. ) 封装成对应的事件并通过属性 initialMulticaster push 广播出去
 
- 最后广播出去的事件如 ( ApplicationStartingEvent ) 会被 SpringApplication 中的 listeners 属性监听处理
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | // SpringApplication.class public ConfigurableApplicationContext run(String... args) { 	listeners.starting(); }
  // SpringApplicationRunListeners  public void starting() {         Iterator var1 = this.listeners.iterator();
          while(var1.hasNext()) {             SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();             listener.starting();         } }
  // EventPublishingRunListeners.class public void starting() {         this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
   | 
 
EventPublishingRunListener 具体操作事件的广播推送如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
   |  // EventPublishingRunListener 事件推送监听器    // Spring 启动, run()的时候立即运行,ApplicationStartingEvent  public void starting() {        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));    }
     // 环境信息准备好并准备创建 ApplicationContext 之前, ApplicationEnvironmentPreparedEvent    public void environmentPrepared(ConfigurableEnvironment environment) {    }
  //ApplicationContext 创建完成,并准备加载 source时调用, ApplicationPreparedEvent    public void contextPrepared(ConfigurableApplicationContext context) {    }
  // ApplicationContext 已经创建并加载,在 refresh() 之前调用, ApplicationPreparedEvent    public void contextLoaded(ConfigurableApplicationContext context) {    }        // Application refresh()后,容器正式启动, ApplicationStartedEvent    public void started(ConfigurableApplicationContext context) {    }
  // Spring 正式运行, ApplicationReadyEvent    public void running(ConfigurableApplicationContext context) {    }
  // 当运行失败时, ApplicationFailedEvent    public void failed(ConfigurableApplicationContext context, Throwable exception) {    }
   | 
 
SpringApplication.run()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
   | public ConfigurableApplicationContext run(String... args) { 	    // 启动 StopWatch,开始记录任务的执行时间         StopWatch stopWatch = new StopWatch();         stopWatch.start();                  // 定义 context         ConfigurableApplicationContext context = null;         Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();                  // 配置 System Property java.awt.headless = true,用于控制台下的调试         this.configureHeadlessProperty();                  // 获取 SpringApplicationRunListeners,实例为 EventPublishingRunListener         SpringApplicationRunListeners listeners = this.getRunListeners(args);                  // 封装SpringApplicationEvent,即 ApplicationStartingEvent 进行广播推送         listeners.starting(); 		 	   // 定义异常集合,用后于catch && handle         Collection exceptionReporters;         try {                  	// 创建应用程序参数类             ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);                          // 根据 WebType 创建 对应的 Environment 对象,用于获取 properties,profile             // 同时EventPublishingRunListeners 广播 ApplicationEnvironmentPreparedEvent             ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);                          // 在 Environment对象中配置需要忽略的 bean 信息             this.configureIgnoreBeanInfo(environment);                          // 打印 banner             Banner printedBanner = this.printBanner(environment);                          // 创建 ApplicationContext (AnnotationConfigApplicationContext)             // 通过 WebType 得到对应的 ApplicationContextClass,通过反射的到对应的ApplicationContext              context = this.createApplicationContext();                          // 通过 SpringFactoriesLoader 获取配置key的 SpringBoot异常报告器             exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);                          // ApplicationContext pre handle             // 1.为Context 设置 environment             // 2.为之前加载的 AppplicationInitializers 遍历 initialize(context),进行上下文初始化             // 3.创建SpringDefinitionLoader,用于加载 xml 或 JavaConfig 中的bean             this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);                          // 刷新应用上下文 ApplicationContext             this.refreshContext(context);                          // 刷新上下文后的额外操作             this.afterRefresh(context, applicationArguments);                          // 停止时间计时             stopWatch.stop();             if (this.logStartupInfo) {                 (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);             }
  		   // 启动加载的 listener list             listeners.started(context);                          // 添加 ApplicationRunners 和 CommandLineRunners 相关的 Runners              this.callRunners(context, applicationArguments);         } catch (Throwable var10) {         	// 这里用于处理之前捕获的异常集合             this.handleRunFailure(context, var10, exceptionReporters, listeners);             throw new IllegalStateException(var10);         }
          try {         	// 启动加载的 listener list             listeners.running(context);             return context;         } catch (Throwable var9) {             this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);             throw new IllegalStateException(var9);         }     }
  | 
 
总结:
启动 Spring Boot 的过程大致分为两部分,一部分为:SpringApplication 的构造过程 和 SpringApplication.run() 具体的运行过程  
SpringApplication 的构造方法主要有以下过程:
- 获取并设置 primarySources, 即程序的入口 Class
 
- 获取设置 webApplicationType
 
- 通过 SpringFactoriesLoader ,加载 spring.factories 中的 Initializers ,找到所有初始化器,并设置属性
 
- 同理,找到所有的应用程序监听器,并设置到 Listeners 属性中
 
- 找到运行的 
main 主类,并设置到属性 mainApplicationClass 
SpringApplication run() 的执行过程如下:
- 启动 StopWatch,开始记录任务的执行时间
 
- 定义 
ApplicationContext,并通过 EventPublishingRunListeners 广播 ApplicationStartingEvent 事件,事件将会被加载的 listeners 监听并处理 
- 创建应用参数类 ApplicationArguments 及根据 WebApplicationType 创建对应的 Environment,用于记录系统中的 Properties
 
- 创建 ApplicationContext
 
- 进行 
prepareContext,对 context 设置environment,并遍历加载的 initializer 初始化 context,最后创建 SpringDefinitionLoader 
refreshContext,完成 bean 的解析,开启 processor 接口等工作 
- 加载的 listeners 进行 start(), running(),同时加入 SpringRunners
 
参考
SpringBoot源码分析之SpringBoot的启动过程
Spring Boot 启动深究SpringApplication执行流程