主配置类(标注了@SpringBootApplication)的main中,SpringApplication.run(主配置类名.class,args)就是分析入口。
总体来说,SpringBoot启动流程分为了两步:
- 创建SpringApplication对象。
- 调用这个对象的run方法。
//SpringApplication.java
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return (new SpringApplication(sources)).run(args);
}
1. SpringApplication的创建
由SpringApplication构造器调用的核心方法initialize。
//SpringApplication.java
private void initialize(Object[] sources) {
//1. 保存主配置类
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//2. 判断当前应用是否为WebApplication,源码中的逻辑:是否导入"javax.servlet.Servlet"和"org.springframework.web.context.ConfigurableWebApplicationContext",存在便是WebApplication
this.webEnvironment = this.deduceWebEnvironment();
//3. 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer后保存起来。(getSpringFactoriesInstance底层的核心调用是SpringFactoriesLoader.loadFactoryNames)【保存的结果见图一】
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//4. 从类路径下找到META-INF/spring.factories配置的所有ApplicationListener(与第三步的操作是相同的)【保存的结果见图二】
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//5. 从多个配置类中找到带main()的主配置类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
2. 创建好的SpringApplication调用run()启动
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//1. IoC引用声明
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
this.configureHeadlessProperty();
//2. 获取SpringApplicationListeners,还是通过getSpringFactoriesInstance从类路径下找到META-INF/spring.factories配置的所有ApplicationListener。
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//3. 回调所有SpringApplicationRunListeners的starting()=====
listeners.starting();
try {
//4. 封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//5.准备环境
/*
* 5.1 getOrCreateEnvironment()创建IoC容器运行环境(包括activeProfiles、defaultProfiles、propertySources、propertyResolver)完成后
* 5.2 回调所有SpringApplicationRunListener的environmentPrepared(),表示环境准备完成
*/
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
//6. 控制台图标打印
Banner printedBanner = this.printBanner(environment);
//7. 反射创建对应的IoC容器(Web的IoC还是普通的IoC?)
context = this.createApplicationContext();
analyzers = new FailureAnalyzers(context);
//8. 准备上下文
/*
* 8.1 保存Environment到IoC容器 context.setEnvironment(environment);
* 8.2 applyInitializers(),回调ApplicationContextInitilizer(在创建SpringApplication阶段保存的所有初始化器)的initialize()
* 8.3 listeners.contextPrepared(),回调所有SpringApplicationRunListener(在创建SpringApplication阶段保存的所有listeners)的contextPrepared()
* 8.4 最后一步listeners.contextLoad()将回调所有SpringApplicationRunListener.contextLoaded()
*/
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//9. 刷新容器:IoC容器初始化(扫描、加载、创建IoC容器中所有组件,包括所有普通配置类、自动配置类、所有@Bean...) -> Sping原理refresh
//如果是Web应用,那嵌入式的Tomcat创建与启动在这一步完成
this.refreshContext(context);
//10. 从IoC容器中获取所有的ApplicationRunner和CommandLineRunner,先后回调callRunner(),也就是具备优先级
this.afterRefresh(context, applicationArguments);
//11. 回调所有SpringApplicationRunListener(在创建SpringApplication阶段保存的所有listeners)的finish()
listeners.finished(context, (Throwable)null);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//12. 整个Spring Boot应用启动完成后返回IoC容器
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
throw new IllegalStateException(var9);
}
}
3. 添加自定义的事件监听
-
实现接口之后,还要配置在类路径下的META-INF/spring.factories中(需要手动创建目录和文件,文件的编写参考spring-boot-autoconfigure包下的META-INF/spring.factories)
(1)ApplicationContextInitializer。
(2)SpringApplicationRunListener,必须声明一个有参构造器(两个参数的类型:SpringApplication,String[])。 -
实现接口之后, 只需要放在IoC容器中(@Component)
(1)ApplicationRunner
(2)CommandLineRunner