07、SpringBoot 源码分析 - SpringApplication启动流程七

news2024/11/13 11:29:47

SpringBoot 源码分析 - SpringApplication启动流程七

  • 初始化基本流程
  • SpringApplication的prepareContext准备上下文
    • postProcessApplicationContext处理
    • applyInitializers初始化器初始化
    • load
  • SpringApplication的refreshContext刷新上下文
    • refresh
      • ServletWebServerApplicationContext的refresh

初始化基本流程

在这里插入图片描述

SpringApplication的prepareContext准备上下文

这里面有干了很多事,他会将最前面获得的初始化器都初始化,然后广播上下文准备好事件,然后这里居然还设置了不能覆盖同名bean定义,这样就避免了用户去捣乱了。最后会把启动类的注册到bean定义里,然后广播上下文加载完成事件。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
   
     
		context.setEnvironment(environment);//配置环境
		postProcessApplicationContext(context);//一些设置处理
		applyInitializers(context);//初始化监听器进行初始化
		listeners.contextPrepared(context);//广播上下文准备好的事件ApplicationContextInitializedEvent
		if (this.logStartupInfo) {
   
     //控制台打启动信息
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
   
     
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
   
     
			((DefaultListableBeanFactory) beanFactory)//不允许同名的bean定义的覆盖
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
   
     
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();//获取启动源集合,就是传给SpringApplication的参数类
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));//注册启动类的bean定义
		listeners.contextLoaded(context);//广播上下文加载完成事件ApplicationPreparedEvent
	}

postProcessApplicationContext处理

就是提前去注册bean名字生成器,资源加载器,还有前面创建的转换器也要放进来。

	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
   
     
		if (this.beanNameGenerator != null) {
   
     
			context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
   
     
			if (context instanceof GenericApplicationContext) {
   
     
				((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
   
     
				((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
		if (this.addConversionService) {
   
     //添加转换器
			context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
		}
	}

applyInitializers初始化器初始化

获取最开始创建的初始化器,遍历每一个初始化器,进行初始化。

	protected void applyInitializers(ConfigurableApplicationContext context) {
   
     
		for (ApplicationContextInitializer initializer : getInitializers()) {
   
     
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
					ApplicationContextInitializer.class);//获取ApplicationContextInitializer接口的泛型类型
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");//context不是requiredType类型是不行的
			initializer.initialize(context);//初始化
		}
	}

load

创建bean定义加载器,进行bean定义的加载,就是把sources注册到bean定义里。

protected void load(ApplicationContext context, Object[] sources) {
   
     
		if (logger.isDebugEnabled()) {
   
     
			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
   
     
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
   
     
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
   
     
			loader.setEnvironment(this.environment);
		}
		loader.load();
	}

	//遍历每一个加载
	int load() {
   
     
		int count = 0;
		for (Object source : this.sources) {
   
     
			count += load(source);
		}
		return count;
	}

根据不同类型加载,最后都是registerBean
在这里插入图片描述

SpringApplication的refreshContext刷新上下文

除了刷新外,还注册了一个钩子

	private void refreshContext(ConfigurableApplicationContext context) {
   
     
		refresh(context);
		if (this.registerShutdownHook) {
   
     
			try {
   
     
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
   
     
				// Not allowed in some environments.
			}
		}
	}

refresh

调用当前上下文AbstractApplicationContext类型的refresh,当前上下文是ServletWebServerApplicationContext类型的,所以会调用到他的refresh

	protected void refresh(ApplicationContext applicationContext) {
   
     
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}

ServletWebServerApplicationContext的refresh

然后他又调用父类的refresh

	@Override
	public final void refresh() throws BeansException, IllegalStateException {
   
     
		try {
   
     
			super.refresh();
		}
		catch (RuntimeException ex) {
   
     
			stopAndReleaseWebServer();
			throw ex;
		}
	}

里面就是springrefresh方法,进行初始化,就不讲了,可以看我写的spring源码文章,其实内部干了不少事情,后面会讲,毕竟前面那么多初始化器初始化了,肯定会对后面spring初始化有所作用。
看看钩子方法,其实就是注册一个关闭线程:
在这里插入图片描述

刷新完成后基本没啥事了,就进行启动完成事件通知,还有一些的ApplicationRunnerCommandLineRunner类型的bean要处理,一般是没有的:
在这里插入图片描述
最后再通知一个运行事件初始化就完成了:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1702710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌开发者账号身份验证不通过?该怎么办?

我们都清楚&#xff0c;随着谷歌上架行业的快速发展&#xff0c;谷歌政策也在不断更新变化&#xff0c;对开发者账号的审核标准也在不断提升。其中一项要求就是&#xff0c;开发者账号需要进行身份验证才能发布应用。 Your identity couldnt be verified&#xff01;“我们无法…

BookStack VS HelpLook两款知识库软件的区别

现在很多企业都会进行知识管理&#xff0c;在这个过程中&#xff0c;选择一个合适的知识库软件是一个不可避免的问题。在众多知识库软件中&#xff0c;HelpLook和BookStack这两款软件备受企业瞩目。不知如何选择&#xff0c;今天LookLook同学就简单介绍一下这两款知识库的区别&…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-24.1,2 SPI驱动实验-SPI协议介绍

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

常用时序逻辑电路模块:移位寄存器

寄存器与移位寄存器 寄存器&#xff1a;数字系统中用来存储二进制数据的逻辑器件。存储N位二进制数据的寄存器需要N个触发器组成。 移位功能&#xff1a;存储代码在脉冲作用下依次左移或右移。 移位寄存器&#xff1a; 移位寄存器中的数据可以在移位脉冲作用下依次逐位右移…

微信小程序打印功能怎么用?

在数字化时代&#xff0c;微信小程序为我们提供了许多便捷的服务&#xff0c;其中就包括打印功能。而琢贝云打印小程序&#xff0c;作为一款功能强大、操作简便的线上打印平台&#xff0c;更是受到了广大用户的青睐。下面&#xff0c;我将为大家介绍如何使用琢贝云打印小程序完…

AI开发初体验:昇腾加持,OrangePi AIpro 开发板

文章目录 一、前言二、板子介绍2.1 拆箱2.2 板子规格2.2.1 常规项目2.2.2 扩展项目2.2.3 操作系统 2.3 点板画面 三、AI程序初体验3.1 新奇的地方3.2 运行第一个AI程序3.2.1 硬件连接3.2.2 串口连接3.2.3 开启外部IP端口3.2.4 查询板子IP地址3.2.5 了解 juypter lab 启动脚本&a…

【ES6】ECMAS6新特性概览(一):变量声明let与const、箭头函数、模板字面量全面解析

&#x1f525; 个人主页&#xff1a;空白诗 &#x1f525; 热门专栏&#xff1a;【JavaScript】 文章目录 &#x1f33f; 引言一、 let 和 const - 变量声明的新方式 &#x1f31f;&#x1f4cc; var的问题回顾&#x1f4cc; let的革新&#x1f4cc; const的不变之美 二、 Arro…

双指针法练习题(2024/5/27)

1 反转字符串 II 给定一个字符串 s 和一个整数 k&#xff0c;从字符串开头算起&#xff0c;每计数至 2k 个字符&#xff0c;就反转这 2k 字符中的前 k 个字符。 如果剩余字符少于 k 个&#xff0c;则将剩余字符全部反转。如果剩余字符小于 2k 但大于或等于 k 个&#xff0c;则…

【管理咨询宝藏114】贝恩为某知名化妆品战略规划方案

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏114】贝恩为某知名化妆品战略…

导入 FDTD 仿真的 S 参数到 INTERCONNECT 的器件中

导入 FDTD 仿真的 S 参数到 INTERCONNECT 的器件中 正文正文 很多时候,仿真链路比较大时,我们可以将仿真的每个部分分隔开来,用 FDTD 计算出每一部分的 S 参数,然后将这些 S 参数导入 INTERCONNECT 中得到最终的仿真结果。这里我们来介绍一下这种方法。 首先,我们从右侧…

洗地机哪个品牌的质量比较好?家用洗地机品牌排行榜

随着科技的迅速发展和生活水平的不断提高&#xff0c;洗地机凭借其集吸尘、拖地和洗地于一体的技术优势&#xff0c;成为了家庭清洁的理想选择。洗地机不仅能够高效清理各种地面污渍&#xff0c;还能同时处理干湿垃圾&#xff0c;极大地提升了清洁效率。然而&#xff0c;市场上…

【SpeedAI科研小助手】2分钟极速解决知网维普重复率、AIGC率过高,一键全文降!文件格式不变,公式都保留的!

知网、维普极速降重、降AIGC率方法 非常简单&#xff0c;打开SpeedAI科研小助手&#xff0c;使用一键降重&#xff0c;上传自己的论文文件&#xff0c;等待即可。 等待弄完了之后&#xff0c;直接下载&#xff0c;可以发现word格式保持不变。直接交就完事了&#xff0c;全程2…

YOLOv10:全面的效率-准确性驱动模型设计

YOLOv10&#xff1a;全面的效率-准确性驱动模型设计 提出背景精细拆分解法双重标签分配一致的匹配度量以效率为导向的模型设计 YOLO v10 总结1. 双重标签分配策略2. 一致匹配度量策略 论文&#xff1a;https://arxiv.org/pdf/2405.14458 代码&#xff1a;https://github.com/T…

Mac 安装 PostgreSQL简易教程

Mac 安装 PostgreSQL简易教程 下载安装包 下载安装包 下载地址 我下载的文件&#xff1a;Postgres-2.7.3-16.dmg 双击 dmg 文件安装 拖拽图标到右边的文件&#xff0c;然后到应用程序中找到 Postgres.app 双击打开。 然后点击 Initialize 按钮 配置$PATH 到命令下工具&#…

智慧管网 | “数字大脑”加速“能源动脉”新升级

行业背景 我国作为全球最大的发展中国家&#xff0c;随着工业化、城镇化的发展&#xff0c;工业企业与居民对原油、天然气消费需求不断增长。而油气管网作为一组连接石油和天然气生产基地、储气库、终端市场等节点的管道网络系统&#xff0c;是油气上下游衔接协调发展的关键环…

148.栈与队列:前K个高频元素(力扣)

代码解决 class Solution { public:// 自定义比较类&#xff0c;用于优先队列&#xff08;小顶堆&#xff09;class mycomparison{public:// 重载操作符&#xff0c;用于比较两个pair&#xff0c;基于pair的第二个值&#xff08;频率&#xff09;bool operator()(const pair&l…

【机器学习】随机梯度下降算法以及优化

一、概述&#xff1a; 什么是梯度下降&#xff1f; 梯度下降法的基本思想可以类比为一个下山的过程。 假设这样一个场景:一个人被困在山上&#xff0c;需要从山上下来(i.e.找到山的最低点&#xff0c;也就是山谷)。但此时山上 的浓雾很大&#xff0c;导致可视度很低。因此&am…

全球伦敦金交易时间每天都一样吗?

伦敦金市场是一个全球化的市场&#xff0c;它全天的交易盘面由亚洲、欧洲和北美市场无缝地连接而成&#xff0c;无论来自世界上什么地方的投资者参与其中&#xff0c;都可以得到全天接近24个小时的交易行情&#xff0c;只要有足够的精力&#xff0c;根本不用担心没有交易获利的…

ResNet残差网络的学习【概念+翻译】

基于何明凯前辈论文的学习 1.主要内容&#xff08;背景&#xff09; 1、首先提了一个base&#xff1a;神经网络的深度越深&#xff0c;越难以训练。 2、原因&#xff1a;因为随着神经网络层数的增加&#xff0c;通常会遇到梯度消失或梯度爆炸等问题&#xff0c;这会导致训练变…

小预算大效果:揭秘品牌如何用创新方法实现低成本传播

说到品牌&#xff0c;我们都知道&#xff0c;没钱是真的难搞。 品牌建设就像跑马拉松&#xff0c;得慢慢来&#xff0c;持续投入&#xff0c;一点一滴积累声誉&#xff0c;这样才能培养出忠实的粉丝团。 但别急&#xff0c;就算资金紧张&#xff0c;我们也有办法让品牌慢慢站…