提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
springboot启动过程源码学习记录
一、创建SpringApplication
new SpringApplication(primarySources).run(args);
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//将所需要的资源加载程序保存下来resourceLoader
this.resourceLoader = resourceLoader;
//判断bean源primarySources是否为空
Assert.notNull(primarySources, "PrimarySources must not be null");
//将主要的bean源保存下来
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断应用是什么类型并保存 (点进去可以看到使用ClassUtils判断)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList<>
//去META-INF类下spring.factories下找到对应的bootstrappers初始启动引导器(org.springframework.boot.Bootstrapper)
(getSpringFactoriesInstances(Bootstrapper.class));
//去META-INF类下spring.factories下找到对应ApplicationContextInitializer初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//去META-INF类下spring.factories下找到对应ApplicationListener应用监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//如图1
this.mainApplicationClass = deduceMainApplicationClass();
}
deduceMainApplicationClass()找到程序中带main函数的 作为程序的主入口
总结: 创建springApplication就是在做准备工作,吧关键的组件去配置文件读取过来保存下来 为启动做准备
二 启动SpringApplication
1.新建一个StopWatch监听计时器 记录应用的启停时间
2.创建引导上下文createBootstrapContext()
(1)初始化一个默认的引导上下文
(2)将刚才从spring.factories中获取到的bootstrap挨个执行初始化方法intitialize()来完成对引导启动器的环境初始化配置
3.将应用配置成headless模式 (自力更生模式) java.awt.headless
4.getRunListeners()
去spring.factories获取所有的SpringApplicationRunListener并保存(运行监听器 为了方便所有监听器在每个阶段进行事件感知 监听)
5.调用所有监听器的starting方法(相当于告诉所有人 我的应用正在启动) 并且打印启动类的类名
6.保存通过命令行传输过来的参数 比如我们启动项目java -jar *.jar --xxx参数 就会通过这个保存下来并执行
7.准备运行时环境prepareEnvironment()
详细方法
(1)getOrCreateEnvironment()
这一步用来返回或创建基础环境信息对象。若当前的环境不为空,则返回当前的环境,否则根据当前的应用类型来返回不同的应用环境,比如我们当前的环境类型为SERVLET,就会返回 StandardServletEnvironment 类型环境
(2)configureEnvironment()
1.首先给环境加上ConversionService类型转换器
2.configurePropertySources(environment, args);
读取所有的配置源的配置属性值
向环境对象中填充了 Servlet 中的初始化参数,以及本机系统的环境变量(System.getenv)与 JVM 的环境变量(System.getProperties)
(3)绑定环境信息ConfigurationPropertySources.attach(environment);
(4)调用所有监听器的environmentPrepared()方法(通知所有的监听器当前环境准备完成)
SpringBoot默认配置文件 application.yml 的加载也在这一步完成,是通过 Spring 的默认实现:EventPublishingApplicationRunListener 来做的工作
(5)将其他对应信息绑定
8.configureIgnoreBeanInfo()配置需要忽略的bean信息,打印Banner
9.createApplicationContext()创建IOC容器并返回一个IOC容器对象
根据当前应用类型创建对应的IOC容器(应用类型为servlet的)
10.context.setApplicationStartup(this.applicationStartup);
IOC容器再来记录我们当前应用的 Startup 事件,将 StartUp 这个信息保存起来
11.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//先给IOC容器将之前配置好的环境设置上
context.setEnvironment(environment);
//后置处理 IOC 容器
postProcessApplicationContext(context);
//应用初始化器,
//1.遍历开始从spring.factories中获取的ApplicationContextInitializer,调用其initialize()对容器进行初始化扩展
//2.各种Initializer有着不同的功能,根据其自己的初始化逻辑对容器做一些扩展初始化操作
applyInitializers(context);
//调用所有SpringApplicationRunListener的contextPrepared(),通知IOC的上下文已经准备好
listeners.contextPrepared(context);
//关闭引导上下文
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 获取的Bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//给容器中注册一些特别的原始的单实例Bean:例如命令行参数、横幅
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
//通知所有的监听器,上下文环境加载完成,调用所有监听器的contextLoaded()
listeners.contextLoaded(context);
}
12.refreshContext(context);刷新IOC容器
spring经典容器初始化过程,创建容器中的所有组件
13.afterRefresh() 容器完成后工作
14.stopWatch.stop(); 监听计时器记录启动结束时间
15.listeners.started(context); 调用所有监听器的started()方法 通知所有监听器程序启动完成!!!
16.callRunners(context, applicationArguments);
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
//获取容器中的ApplicationRunner
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//获取容器中的CommandLineRunner
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
//排序
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
//如果有 调用其run方法
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
17.出现错误调用监听器的failed()方法,通知监控当前应用启动失败!!
18.listeners.running(context);调用监听器的running()方法 通知所有的监听器项目已经跑起来了
19.SpringBoot应用的启动成功,返回一个IOC容器
总结
菜鸟学习学习中…