SpringBoot启动流程总结
1.导语
//以下是一个SpringBoot应用的标准入口:
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
//SpringApplication.run 内部是这样的:先创建一个 SpringApplication 对象,然后调用他的run方法。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
所以想要了解清楚 SpringBoot 启动流程,相当于了解 SpringApplication 的 构造方法 和 run方法。
2.构造方法详解
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断应用类型,会有三种情况:
// NONE:非web应用
// SERVLET:普通web应用
// REACTIVE:响应式web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从 META-INF/spring.factories 文件中获取如下内容
// 获取 注册初始化器:在 run 方法中的 createBootstrapContext(); 里会被使用
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 获取 容器初始化器:在 run 方法中的 prepareContext( ... ); 里会被使用
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 获取 监听器:在 run 方法中 listeners.xxx 时被使用
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
3.run方法详解
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 第一步:创建监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布事件:开始启动
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 第二步:准备环境变量
// 把一系列设置整合成 environment,包括 系统变量、JVM参数、启动参数(args)、配置文件(application、bootstrap等)
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
Banner printedBanner = printBanner(environment);
// 第三步:创建空容器
// 根据 new 时判断的 web类型(webApplicationType),创建对应类型的容器
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 第四步:准备容器
// 把前面准备的东西注入进去,包括 环境变量(environment)、事件监听器(listeners)、启动参数(applicationArguments)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 第五步:启用容器
// 解析@SpringBootApplication注解,加载自动配置类
// 进行Bean的扫描、加载、实例化、依赖注入
// 如果是Web应用,会启动一个内嵌式的Web服务器比如Tomcat
refreshContext(context);
// 容器初始化后的操作,是个空方法,要使用需要继承并重写
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 发布事件:已启动
listeners.started(context, timeTakenToStartup);
// 执行启动后的自定方法:
// 实现 ApplicationRunner、CommandLineRunner 接口
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
if (ex instanceof AbandonedRunException) {
throw ex;
}
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 检查应用是否还在运行
if (context.isRunning()) {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
// 发布事件:准备就绪
listeners.ready(context, timeTakenToReady);
}
}
catch (Throwable ex) {
if (ex instanceof AbandonedRunException) {
throw ex;
}
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
// 返回Bean容器
return context;
}