2021-09-24 springboot启动流程学习记录

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

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函数的 作为程序的主入口
图1

总结: 创建springApplication就是在做准备工作,吧关键的组件去配置文件读取过来保存下来 为启动做准备

二 启动SpringApplication

1.新建一个StopWatch监听计时器 记录应用的启停时间
!\外链入图转存中...]/img-PvldHbKg-155b96647a8ab51213adf1b921d.pn
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容器

总结

菜鸟学习学习中…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值