SpringBoot启动流程
SpringBoot启动流程
首先 Springboot 框架总体来说还是基于 Spring 进行的优化和加强!
所以其总体核心还是没有变化 也就是 ApplicationContext Ioc容器
而SpringBoot 相较于 Spring 的特点和核心是autoconfiguration和springboot 中的 ==spring.factories==
该文件是实现springboot自动装配的重要部分
1、程序入口
首先会有一个程序的入口,进行开启
@SpringBootApplication
public class SpringTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringTestApplication.class, args);
}
}
-
程序入口要被
@SpringBootApplication
给标注 -
@SpringBootApplication
点进去可以看见有三个重要注解-
@SpringBootConfiguration //声明该类为SpringBoot配置类 @EnableAutoConfiguration //开启配置的自动装配 @ComponentScan //开启自动扫描注解
-
2、启动初始化器
他会执行如下命令
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
...
//资源加载器默认根据前面判断,这里为null
this.resourceLoader = resourceLoader;
//设置主要源,也就是我们的启动主类
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//这里是关键,这里会判断当前SpringBoot应用程序是否为Web项目,并返回当前的项目类型
//deduceFromClasspath是根据类路径下判断是否包含SpringBootWeb依赖,如果不包含就是NONE类型,包含就是SERVLET类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//获取并设置所有ApplicationContextInitializer实现,这些都是应用程序上下文初始化器
//这个接口用于在 Spring 容器执行 onRefresh 方法刷新之前执行一个回调函数
//通常用于向 SpringBoot 启动的容器中注入一些属性,比如ContextIdApplicationContextInitializer就是
//将配置中定义的 spring.application.name 属性值设定为应用程序上下文的ID
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置应用程序监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//找到并设定当前的启动主类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
new 一个 SpringApplication 然后去走 SpringApplication的构造方法
-
判断是否为web应用,查看是否包含web依赖
-
==通过
getSpringFactoriesInstances
去获得默认的初始化器==-
private <T> List<T> getSpringFactoriesInstances(Class<T> type, ArgumentResolver argumentResolver) { return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver); }
-
public static SpringFactoriesLoader forDefaultResourceLocation(@Nullable ClassLoader classLoader) { return forResourceLocation("META-INF/spring.factories", classLoader); }
-
其实总的来讲就是去
spring.factories
文件下寻找到默认的初始化器并装配
-
-
获取应用上下文初始化器 ApplicationContextInitializer
-
最后找到并设定当前的类为运行主类,也就是传进来的xxxApplication.class
3、获取配置
第二步将Spring Application的构造器走完后 接下来运行如下
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
//获取所有的SpringApplicationRunListener,并通知启动事件,默认只有一个实现类EventPublishingRunListener
//EventPublishingRunListener会将初始化各个阶段的事件转发给所有监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//环境配置,包括我们之前配置的多环境选择
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//打印Banner,从这里开始我们就可以切切实实看到运行状了
Banner printedBanner = this.printBanner(environment);
//创建ApplicationContext,也就是整个Spring应用程序的IoC容器,SSM阶段已经详细介绍过,注意这里会根据构造时得到的类型,创建不同的ApplicationContext实现类(比如Servlet环境下就是Web容器)
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//对ApplicationContext进行前置处理,这里会将创建对象时设定的所有ApplicationContextInitializer拿来执行一次initialize方法,这也验证了我们之前的说法,这一步确实是在刷新容器之前进行的
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//执行ApplicationContext的refresh方法,刷新容器初始化所有的Bean,这个也在SSM阶段详细介绍过了
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
//因为所有的Bean都已经加载,这里就可以调用全部的自定义Runner实现了
this.callRunners(context, applicationArguments);
...
//结束
return context;
}
- 将后续启动事件通知,启动监听器 SpringApplicationRunListener
- 读取配置 application.yml
- 打印banner,这个时候已经可以看到我们后续的一个log了
- 然后就去创建整个Spring最核心的 ==ApplicationContext==
- 初始化所有的Bean并装配进容器中
- 返回Context 也就是返回容器
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
MianJu —— 这只是一个 Title 而已~!
喜欢就支持一下吧