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

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要处理,一般是没有的:
在这里插入图片描述
最后再通知一个运行事件初始化就完成了:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣538. 把二叉搜索树转换为累加树

Problem: 538. 把二叉搜索树转换为累加树 文章目录 题目描述思路复杂度Code 题目描述 思路 利用二叉搜索树中序遍历的特性&#xff0c;**降序遍历&#xff08;此处是想表达先遍历其右子树再遍历其左子树这样遍历的过程中每个节点值得大小排序是降序得&#xff09;**其节点&…

Mybatis-全局配置文件多数据库支持

这里我们来做一个对比试验&#xff0c;将上门课中使用hibernate做的权限控制项目&#xff0c;从mysql数据库转移到orcale数据库&#xff0c;然后我们在让现在的mybatis入门demo也从使用mysql数据库改orcale&#xff0c;对比一下两者之间的区别&#xff1a; <dependency>…

【C++】二分查找:在排序数组中查找元素的第一个和最后一个位置

1.题目 难点&#xff1a;要求时间复杂度度为O(logn)。 2.算法思路 需要找到左边界和右边界就可以解决问题。 题目中的数组具有“二段性”&#xff0c;所以可以通过二分查找的思想进行解题。 代码&#xff1a; class Solution { public:vector<int> searchRange(vect…

【排序算法】选择排序以及需要注意的问题

选择排序的基本思想&#xff1a;每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 第一种实现方法&#xff1a; void SelectSort(int* arr, int n) {for (int j 0…

阿里云百炼大模型使用

阿里云百炼大模型使用 由于阿里云百炼大模型有个新用户福利&#xff0c;有免费的4000000 tokens&#xff0c;我开通了相应的服务试试水。 使用 这里使用Android开发了一个简单的demo。 安装SDK implementation group: com.alibaba, name: dashscope-sdk-java, version: 2.…

DAMA数据管理知识体系必背18张框图

近期对数据管理知识体系中比较重要的框图进行了梳理总结,总共有18张框图,供大家参考。主要涉及数据管理、数据治理阶段模式、数据安全需求、主数据管理关键步骤,主数据架构、DW架构、数据科学的7个阶段、数据仓库建设活动、信息收敛三角、大数据分析架构图、数据管理成熟度等…

精品丨快速申请免费https证书

https域名证书对提高网站排名有一定的好处&#xff0c;所以当今很多企业为了给网站一个好的安全防护&#xff0c;就会去申请该证书。如今很多企业虽然重视网站的安全防护&#xff0c;但是也重视成本&#xff0c;所以为了节约成本会考虑申请免费的https证书。 第一个好处 企业不…

如何在 DigitalOcean Droplet 云主机上创建 Ubuntu 服务器

在本文中&#xff0c;你将通过 DigitalOcean 的管理面板创建一个 Ubuntu 服务器&#xff0c;并将其配置为使用你的 SSH 密钥。设置好服务器后&#xff0c;你可以在其上部署应用程序和网站。 本教程是DigitalOcean云课程简介的一部分&#xff0c;它指导用户完成将应用程序安全地…

SpringBoot+Vue开发记录(七)-- 跨域文件与Restful风格

本篇文章的主要内容是关于项目的跨域配置和给项目添加restful风格接口。 重点是文件粘贴 文章目录 一、 跨域二、Restful风格1. 什么是restful风格&#xff1f;2. 项目文件结构3. 新建文件4. 在Controller中进行修改 一、 跨域 跨域问题暂时也就那样&#xff0c;解决方法就是…

Unity入门理论+实践篇之Luna

创建世界的主角 父子物体 首先创建一个cube物体 可以观察到其在2D视角下的坐标为&#xff08;0&#xff0c;0&#xff09; 此时将cube物体拖拽到ldle_0下&#xff0c;如图所示&#xff0c;并将其坐标值改为&#xff08;2&#xff0c;2&#xff09; 此时再将ldle_0物体的坐标…

huggingface 笔记:查看GPU占用情况

0 准备部分 0.1 创建虚拟数据 import numpy as npfrom datasets import Datasetseq_len, dataset_size 512, 512 dummy_data {"input_ids": np.random.randint(100, 30000, (dataset_size, seq_len)),"labels": np.random.randint(0, 1, (dataset_size…

Markdown魔法手册:解锁高效写作的新技能

边使用边更新0.0... 文章目录 一、如何在Markdown中插入表情&#xff1f;二、文字样式设置1.文本颜色设置2.文本字号设置3.文本字体设置4. 实战演练5.黄色高亮 一、如何在Markdown中插入表情&#xff1f; 在Markdown中插入表情&#xff08;emoji&#xff09;的方法取决于你使用…

02.并发编程基础概念

在正式学习 Java 的并发编程之前&#xff0c;我们需要熟悉和学习几个并发编程的基础概念。 1 进程和线程 1.1 进程 我们常说的是应用程序&#xff0c;也就是 app&#xff0c;由指令和数据组成。但是当我们不运行一个具体的 app 时&#xff0c;这些应用程序就是放在磁盘(也包括…

安装pip install xmind2image失败,4种安装pip install xmind2image在temunx高级终端的失败,却又意外发现

~ $ ~ $ ![在这里插入图片描述](https://img-blog.csdnimg.cn/b59cbb49c3e14a3bbec5675164a14009.png)#!/bin/bash # 创建一个新的空白XMind文件 xmind_dir ( m k t e m p − d ) x m i n d f i l e n a m e ′ t e s t . x m i n d ′ x m i n d p a t h " (mktemp -d…

生命在于学习——Python人工智能原理(1.2)

一、人工智能的基本知识 6、新一代人工智能驱动因素 &#xff08;1&#xff09;数据量爆发性增长。 &#xff08;2&#xff09;计算能力大幅提升 &#xff08;3&#xff09;深度学习等算法发展 &#xff08;4&#xff09;移动AI创新应用牵引 7、人工智能关键技术 &#x…

Value-Based Reinforcement Learning(1)

Action-Value Functions Discounted Return&#xff08;未来的reward&#xff0c;由于未来存在不确定性&#xff0c;所以未来的reward 要乘以进行打折&#xff09; 这里的依赖actions &#xff0c;和states 这里 Policy Function : &#xff0c;表达了action的随机性 S…

压缩能力登顶 小丸工具箱 V1.0 绿色便携版

平常录制视频或下载保存的视频时长往往都很长&#xff0c;很多时候都想要裁剪、 截取出一些“精华片段”保留下来&#xff0c;而不必保存一整个大型视频那么浪费硬盘空间… 但如今手机或电脑上大多数的视频剪辑软件&#xff0c;切割视频一般都要等待很长时间导出或转换&#…

【Text2SQL】Spider 数据集

论文&#xff1a;Spider: A Large-Scale Human-Labeled Dataset for Complex and Cross-Domain Semantic Parsing and Text-to-SQL Task ⭐⭐⭐⭐⭐ EMNLP 2018, arXiv:1809.08887 Dataset: spider GitHub: github.com/taoyds/spider 一、论文速读 本文提出了 Text2SQL 方向的…

Linux更改系统中的root密码

Linux里面的root密码忘记了怎么办&#xff1f; 1 更改系统中的 root 密码 &#xff08;1&#xff09;键盘 CtrlAltT 快捷键打开终端。 &#xff08;2&#xff09;在终端窗口中输入以下代码&#xff1a; sudo passwd root &#xff08;3&#xff09;输入锁屏密码 &#xf…

C#同花顺下单 模拟操作版接口实现

C#同花顺下单 模拟操作版接口的实现 采用C#编程语言实现&#xff0c;对同花顺下单界面自动控制&#xff0c;将实现方法封装为DLL可以任意使用&#xff0c;支持几乎所有券商&#xff0c;不需要更换特定的券商。 比如当下最流行的QMT量化软件&#xff0c;仍然受限于特定的券商&a…