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);//广播上下文准备好的事件ApplicationContextInitializedEventif (this.logStartupInfo) {//控制台打启动信息logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory 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 sourcesSet<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

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

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

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

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

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

相关文章

8.什么是HOOK

程序编译的本质是&#xff0c;首先计算机它只能看得懂机器码也就是只能看得懂数字&#xff0c;机器码学起来很费劲然后就创造了编译器这个东西&#xff0c;编译器它懂机器语言所以它可以跟机器沟通&#xff0c;而我们人可以跟编译器沟通&#xff0c;人跟编译器的语言就是各种各…

[Vulnhub]Vulnix 通过NFS挂载+SSH公钥免密登录权限提升

端口扫描 Server IP AddressPorts Open192.168.8.103TCP:22/tcp, 25/tcp, 79/tcp, 110/tcp, 111/tcp, 143/tcp, 512/tcp, 513/tcp, 514/tcp, 993/tcp, 995/tcp, 2049/tcp, 37522/tcp, 42172/tcp, 43219/tcp, 47279/tcp, 54227/tcp $ nmap -p- 192.168.8.103 -sV -sC --min-ra…

P1134 [USACO3.2] 阶乘问题

题目传送门&#xff1a; P1134 [USACO3.2] 阶乘问题 29分代码 #include<bits/stdc.h>using namespace std;int main() {int n;cin>>n;unsigned long long s1;for(int i1;i<n;i){s*i;while(s>10){if(s%100) s/10;else ss%10;}}cout<<s%10<<en…

MyBatis系统学习 - 使用Mybatis完成查询单条,多条数据,模糊查询,动态设置表名,获取自增主键

上篇博客我们围绕Mybatis链接数据库进行了相关概述&#xff0c;并对Mybatis的配置文件进行详细的描述&#xff0c;本篇博客也是建立在上篇博客之上进行的&#xff0c;在上面博客搭建的框架基础上&#xff0c;我们对MyBatis实现简单的增删改查操作进行重点概述&#xff0c;在MyB…

P459 包装类Wrapper

包装类的分类 1&#xff09;针对八种基本数据类型相应的引用类型——包装类。 2&#xff09;有了类的特点&#xff0c;就可以调用类中的方法。 Boolean包装类 Character包装类 其余六种Number类型的包装类 包装类和基本数据类型的相互转换 public class Integer01 {publi…

一文入门ZooKeeper

简介 官网&#xff1a;https://zookeeper.apache.org/index.html 分布式服务协调组件&#xff0c;Google Chubby的开源实现。解决分布式应用中的以下问题&#xff1a;配置管理、命名服务&#xff08;Naming Service&#xff09;、集群管理、统一命名服务、状态同步。 用于解决…

清理这8种微信好友,每年多赚30万,看完让你涨知识!

为什么我们通讯录里面有很多好友&#xff0c;而我们却总是过很清贫&#xff1f;为什么我们通讯录本身有几千的好友&#xff0c;却通过微信好友却无法变现&#xff1f; 在我第二次创业失败的时候&#xff0c;我从整理朋友圈&#xff0c;整理微信通讯录&#xff0c;到清理微信好…

解决文件夹打开出错问题:原因、数据恢复与预防措施

在我们日常使用电脑或移动设备时&#xff0c;有时会遇到一个非常棘手的问题——文件夹打开出错。这种错误可能会让您无法访问重要的文件和数据&#xff0c;给工作和生活带来极大的不便。本文将带您深入了解文件夹打开出错的原因&#xff0c;并提供有效的数据恢复方案&#xff0…

线程池中的阻塞队列和拒接策略

在 Java 中&#xff0c;线程池使用 java.util.concurrent 包中的 ThreadPoolExecutor 来管理线程。ThreadPoolExecutor 提供了几种不同类型的阻塞队列和拒绝策略&#xff0c;以便处理线程池中的任务调度和资源管理。 1. 阻塞队列&#xff08;Blocking Queue&#xff09; 阻塞…

最新Java面试

1.和equals有什么区别&#xff1f; 可以比较基本数据类型和引用数据类型&#xff0c;两端如果是基本数据类型就是判断值是否相同&#xff0c;两端是引用数据类型就是比较内存地址是否相同。 equals()比较引用数据类型&#xff0c;equals在重写之后&#xff0c;判断两个对象的…

【网络协议】应用层协议--HTTP

文章目录 一、HTTP是什么&#xff1f;二、HTTP协议工作过程三、HTTP协议1. fiddler2. Fiddler抓包的原理3. 代理服务器是什么?4. HTTP协议格式1.1 请求1.2 响应 四、认识HTTP的请求1.认识HTTP请求的方法2.认识请求头&#xff08;header&#xff09;3.认识URL3.1 URL是什么&…

CPU 亲和性--sched_setaffinity()函数

sched_setaffinity – 将线程&进程运行在期望的CPU核心上 CPU亲和性 是指进程或线程在运行时倾向于在某个或某些CPU核心上执行&#xff0c;而不是随机或频繁地在不同的核心之间切换。 CPU亲和性利用CPU缓存的局部性&#xff0c;减少缓存失效和进程或线程迁移的开销&#x…

SparkSQL入门

1、SparkSQL是什么&#xff1f; 结论&#xff1a;SparkSQL 是一个即支持 SQL 又支持命令式数据处理的工具 2、SparkSQL 的适用场景&#xff1f; 结论&#xff1a;SparkSQL 适用于处理结构化数据的场景&#xff0c;而Spark 的 RDD 主要用于处理 非结构化数据 和 半结构化数据 …

掌握ASPICE标准:汽车软件测试工程师的专业发展路径

掌握ASPICE标准&#xff1a;汽车软件测试工程师的专业发展路径 文&#xff1a;领测老贺 随着新能源汽车在中国的蓬勃发展&#xff0c;智能驾驶技术的兴起&#xff0c;汽车测试工程师的角色变得愈发关键。这一变革带来了前所未有的挑战和机遇&#xff0c;要求测试工程师不仅要具…

Leetcode 3161. Block Placement Queries

Leetcode 3161. Block Placement Queries 1. 解题思路2. 代码实现 题目链接&#xff1a;3161. Block Placement Queries 1. 解题思路 这一题没有搞定&#xff0c;后来是看了答案才多少有了些思路的&#xff0c;感觉人生真的是玄学拉满&#xff0c;每次我休息一整天完全没有学…

解决git克隆项目出现fatal无法访问git clone https://github.com/lvgl/lvgl.git

Windows 11系统 报错 $ git clone https://github.com/lvgl/lvgl.git Cloning into lvgl... fatal: unable to access https://github.com/lvgl/lvgl.git/: Failed to connect to github.com port 443 after 21141 ms: Couldnt connect to server 解决方法 git运行这两段代码…

创新实训2024.05.26日志:落地基于硬盘的数据库服务

1. 需求任务列表 以下描述易学大模型软件的web应用的功能。 用户注册 用户邮箱&#xff0c;密码&#xff0c;验证码开启官方邮箱&#xff0c;用来发验证码&#xff08;QQ 网易都支持开启smtp协议&#xff0c;找教程&#xff0c;用邮箱不用手机号是为了省买发短信云服务的钱&a…

ASP+ACCESS客户管理信息系统

摘要 本文介绍了客户管理系统的实现方法。目的在于让大家共享学习和运用这一语言的体会和收获。本系统是Internet/Intranet环境下面向电子商务的客户管理&#xff0c;通过企业管理技术、电子商务和信息技术的高度集成&#xff0c;讨论了客户管理系统的系统构架、系统的工作…

Rust之初识

1、Rust Linux安装 登录进入linux以后&#xff0c;执行&#xff1a; curl --proto https --tlsv1.2 https://sh.rustup.rs -sSf | sh当提示&#xff1a; Rust is installed now. Great!意味着安装成功了。打开另一个shell页&#xff0c;查看&#xff1a;rustc --version&#x…

栈和队列的基本见解

1.栈 1.1栈的基本概念和结构&#xff1a; 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出的原则。 压栈&#xff1a;栈的插入操作叫做进栈/压栈…