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执行流程