spring容器的启动流程

        spring容器的启动流程是一个面试中比较难答的题目。这块内容比较复杂,回答的时候如果想到什么回答什么,很容易把面试官绕晕。因此比较好的回答方式就是,先理清一个大致的启动流程,再根据面试官的问题细说小点。

这里我们从AnnotationConfigApplicationContext着手分析源码:

说明:这里通过AnnotationConfigApplicationContext扫描com.test包下所有被注解修饰的bean对象,创建了一个applicationContext对象(spring容器)。

这里的类A被@Component注解标识了,因此会被放进applicationContext上下文中。再通过getBean方法,就可以获取A的实例对象。

注意:关于spring容器的启动有很多种方式,比如说ClassPathApplicationContext,通过XML的方式启动一个spring容器。但没有annotation这种注解式开发更方便。


1 构造方法

跟进AnnotationConfigApplicationContext的构造方法可以看到:

1.1 this 方法

跟进这个this方法:

说明:

  1. StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create"); 这行代码主要用于启动一个名为"spring.context.annotated-bean-reader.create"的启动步骤,它是用于计算和监控Spring应用的启动时间,主要用于性能的跟踪监控。

  2. this.reader = new AnnotatedBeanDefinitionReader(this); 这行代码创建了一个AnnotatedBeanDefinitionReader实例,并将其赋值给AnnotationConfigApplicationContextreader成员变量。AnnotatedBeanDefinitionReader类主要用于从注解化的类中读取Bean定义信息,它是Spring处理注解主要的类。

  3. createAnnotatedBeanDefReader.end(); 这行代码结束了"spring.context.annotated-bean-reader.create"的启动步骤,主要用于性能的跟踪监控。

  4. this.scanner = new ClassPathBeanDefinitionScanner(this); 这行代码创建了一个ClassPathBeanDefinitionScanner实例,并将其赋值给AnnotationConfigApplicationContextscanner成员变量。ClassPathBeanDefinitionScanner类主要用于从classpath下的类文件中扫描Bean定义信息


1.2 scan 方法

详细解释如下:

  1. Assert.notEmpty(basePackages, "At least one base package must be specified"); 这行代码用于判断方法参数basePackages是否为空。如果为空,它将抛出一个IllegalArgumentException异常,消息为"At least one base package must be specified"。

  2. StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan").tag("packages", () -> {return Arrays.toString(basePackages);}); 这行代码启动一个名为"spring.context.base-packages.scan"的启动步骤,并标记了"packages"标签(其值为传入的basePackages)。这也是用于计算和监控Spring应用启动时间、性能跟踪。

  3. this.scanner.scan(basePackages); 这行代码使用之前在构造函数里面初始化的scanner(一个ClassPathBeanDefinitionScanner实例)来扫描指定的包basePackages。在这个过程中,scanner将查找所有包及其子包下的类,如果这个类符合Spring Bean的定义(比如被@Component, @Service, @Repository, @Controller等注解标注的类),那么scanner就会将这个类作为一个Bean定义并注册到Spring上下文。

  4. scanPackages.end(); 这行代码结束了之前启动的"spring.context.base-packages.scan"步骤。同样地,这个步骤也主要用于性能跟踪。

简单来说,scan方法就是:用于扫描指定的基础包,以查找并注册Bean定义。


1.3 refresh 方法(重难点)

public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {// 开启一个启动步骤记录器,用于记录开始刷新上下文StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 刷新前预处理,准备刷新上下文this.prepareRefresh();// 获取在容器初始化时创建的BeanFactory(我们后面取类都通过这个BeanFactory中加载出来)ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();// 准备Bean工厂,BeanFactory的预处理工作,回向容器中添加一些组件this.prepareBeanFactory(beanFactory);try {// 处理Bean工厂(子类重写该方法,可以实现在BeanFactory创建并预处理完成后做进一步的设置)this.postProcessBeanFactory(beanFactory);// 开启一个启动步骤记录器,用于记录开始处理Bean后置处理器StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// 在BeanFactory初始化之后执行BeanFactory的后置处理器this.invokeBeanFactoryPostProcessors(beanFactory);// 注册Bean后置处理器。它的主要作用就是干预Spring初始化Bean的流程,完成代理、自动注入、循环依赖等功能。this.registerBeanPostProcessors(beanFactory);// 结束Bean后置处理器步骤记录beanPostProcess.end();// 初始化Messagesource组件,主要是用于国际化this.initMessageSource();// 初始化应用事件广播器this.initApplicationEventMulticaster();// 执行刷新回调方法(留给子类重写的方法,在容器刷新时可以自定义一些逻辑)this.onRefresh();// 注册监听器(有了监听器之后,就可以接收上面事件广播器广播的消息了)this.registerListeners();// 完成Bean工厂的初始化,主要作用是初始化所有剩下的单例Beanthis.finishBeanFactoryInitialization(beanFactory);// 完成刷新,发布容器刷新完成的事件this.finishRefresh();} //以下是容器启动失败的场景,可以不过多深究catch (BeansException var10) {// 如果在上下文初始化过程中遇到异常,记录警告日志并取消刷新尝试if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);}// 销毁所有Beanthis.destroyBeans();// 取消刷新this.cancelRefresh(var10);// 抛出异常throw var10;} finally {// 重置公共缓存this.resetCommonCaches();// 结束刷新步骤记录contextRefresh.end();}}}

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

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

相关文章

RHCE——DNS域名解析服务器、selinux、防火墙

1、DNS简介 DNS ( Domain Name System )是互联网上的一项服务,它作为将域名和 IP 地址相互映射的一个分布式 数据库,能够使人更方便的访问互联网。 DNS 系统使用的是网络的查询,那么自然需要有监听的 port 。 DNS 使…

使用和删除数据库

复习: 1. 查看所有的数据库 show databases; 2. 创建属于自己的数据库 create database 数据库名; create database if not exists 数据库名; create database if not exists 数据库名 character set utf8mb4 | collate utf8mb4_0900_ai_ci; 强烈建议在创建数…

Spring Boot集成iText实现电子签章

文章目录 一 电子签章1.1 什么是电子签章1.2 签名流程1.3 技术选型 二 实战2.1 生成数字证书2.2 生成印章图片2.3 PDF 签名 一 电子签章 1.1 什么是电子签章 基于《中华人民共和国电子签名法》等相关法规和技术规范,具有法律效力的电子签章一定是需要使用 CA 数字…

第5章 中级控件

第 5 章 中级控件 bilibili学习地址 github代码地址 本章介绍App开发常见的几类中级控件的用法,主要包括:如何定制几种简单的图形、如何使用几种选 择按钮、如何高效地输入文本、如何利用对话框获取交互信息等,然后结合本章所学的知识&…

Kubernetes:(四)kubectl命令

文章目录 一、kubectl命令1.查看版本信息 kubectl version2.列出 Kubernetes API 中所有可用的资源及其相关信息 kubectl api-resources3.配置kubectl自动补全 source <(kubectl completion bash)4.查看集群信息 kubectl cluster-info5.node节点查看日志 journalctl -u kube…

互联网人辞职的20条理由,你中了几条?

互联网行业压力大、内卷是众所周知的&#xff0c;想要辞职的念头往往只在一瞬间。 他们想要离职的理由虽然千奇百怪&#xff0c;但每一条都很扎心。 小码在网上搜集了互联网人想要辞职的20条理由&#xff0c;来看看你中了几条吧&#xff1f; 最能戳中你的“辞职理由”是什么呢…

https://huggingface.co/上的模型无法用linux服务器clone怎么办(只需要稍微改一下网址,就可以切换到镜像下载)

问题描述&#xff1a; 在ubuntu系统上&#xff0c;使用如下命令&#xff0c;克隆仓库&#xff0c;报无法访问错误&#xff1a; git clone https://huggingface.co/distilbert/distilroberta-base通用解决方案&#xff1a; 把下面部分更换&#xff1a; https://huggingface.…

使用传感器融合进行3D激光雷达点云运动补偿

此示例展示了如何通过融合来自全球定位系统 (GPS) 和惯性测量单元 (IMU) 传感器的数据来补偿由于自我车辆运动而导致的点云失真。此示例的目标是补偿点云数据中的失真并准确地重新创建周围环境。 文章目录 概述坐标系预处理激光雷达数据预处理 GPS 数据结合 GPS、IMU 和激光雷达…

请看,小白是如何三步速成ComfyUI?

前言 ComfyUI —三步速成秘籍— 嘿&#xff0c;小伙伴们&#xff01; 我是一个刚刚踏入GEO AI实验室的新鲜面孔&#xff0c; 一个对AI设计充满无限好奇的新手。 在这个充满创意和科技感的实验室里&#xff0c; 我只用了短短三个步骤&#xff0c; 就掌握了ComfyUI 。 你…

输电线路火灾隐患监测系统功能与应用是什么?

答&#xff1a;大家好&#xff01;今天我们来聊聊输电线路火灾隐患监测系统TLKS-PMG-DF。这款装置凭借其强大的功能和广泛的应用领域&#xff0c;正在成为电力巡检和山火防控的重要工具。下面&#xff0c;我们就来详细了解一下它的功能与应用吧&#xff01;这款装置配备了先进的…

《高频电子线路》 —— 高频谐振功放

文章内容来源于【中国大学MOOC 华中科技大学通信&#xff08;高频&#xff09;电子线路精品公开课】&#xff0c;此篇文章仅作为笔记分享。 高频谐振功放 主要目的就是功率放大以及高效率。 基本电路原理 高频谐振功放的基本电路&#xff0c;总体上也是由放大管和并联谐振回路…

Java阶段三01

第3章-第1节 一、知识点 maven的简介、安装和使用、仓库管理、项目构建、多模块项目、依赖管理 二、目标 学习了解什么是maven 能够配置maven 使用maven创建项目 掌握maven创建多模块项目的方式 掌握maven的依赖管理和项目构建 三、内容分析 重点 maven的安装和使用 …

【Docker】构建Linux云桌面环境

目录 一、说明 二、离线安装Docker 1&#xff09;将下载的包上传到服务器上去 2&#xff09;安装docker 3) 启动docker 4&#xff09;配置加速器 三、安装云桌面镜像 四、启动云桌面 方式一&#xff1a;docker命令直接运行 方式二&#xff1a;docker-compose方式 五…

【ArcGIS Pro实操第4期】绘制三维地图

【ArcGIS Pro实操第4期】绘制三维地图 ArcGIS Pro绘制三维地图-以DEM高程为例参考 如何使用ArcGIS Pro将栅格数据用三维的形式进行表达&#xff1f;在ArcGIS里可以使用ArcScene来实现&#xff0c;ArcGIS Pro实现原理跟ArcScene一致。由于Esri未来将不再对ArcGIS更新&#xff0c…

“震惊!消费满额即领高额返现,循环购物模式揭秘“

购物满额赠高额返现&#xff0c;每日还能领现金&#xff1f;资金还能提现&#xff1f;这听起来简直像天方夜谭。商家难道真的在无条件发放资金&#xff1f; 大家好&#xff0c;我是电商策略专家吴军。 今天&#xff0c;我要揭秘一种前沿的商业模式——循环消费回馈模式。 这种…

Leetcode 第 420 场周赛题解

Leetcode 第 420 场周赛题解 Leetcode 第 420 场周赛题解题目1&#xff1a;3324. 出现在屏幕上的字符串序列思路代码复杂度分析 题目2&#xff1a;3325. 字符至少出现 K 次的子字符串 I思路代码复杂度分析 题目3&#xff1a;3326. 使数组非递减的最少除法操作次数思路代码复杂度…

Unity3D学习FPS游戏(3)玩家第一人称视角转动和移动

前言&#xff1a;上一篇实现了角色简单的移动控制&#xff0c;但是实际游戏中玩家的视角是可以转动的&#xff0c;并根据转动后视角调整移动正前方。本篇实现玩家第一人称视角转动和移动&#xff0c;觉得有帮助的话可以点赞收藏支持一下&#xff01; 玩家第一人称视角 修复小问…

代码随想录算法训练营第十二天(补) 二叉树| 二叉树理论知识、深度优先遍历、广度优先遍历

目录 一、二叉树理论基础 &#xff08;一&#xff09;二叉树的种类 二叉搜索树 平衡二叉搜索树 &#xff08;二&#xff09;二叉树的存储 &#xff08;三&#xff09;二叉树的遍历 &#xff08;四&#xff09;二叉树的定义 二、二叉树的递归遍历 三、二叉树的层序遍历 …

在线教育系统源码开发详解:网校培训平台搭建的核心技术

本篇文章&#xff0c;笔者将详细介绍在线教育系统源码的开发过程&#xff0c;重点聚焦网校培训平台搭建的核心技术&#xff0c;以期为有意从事在线教育行业的开发者提供实用的参考。 一、在线教育系统的构成 前端负责用户的交互体验&#xff0c;后端处理业务逻辑&#xff0c;…

利士策分享,赚大钱与赚小钱的哲学,选大还是小?

利士策分享&#xff0c;赚大钱与赚小钱的哲学&#xff0c;选大还是小&#xff1f; 在商海浮沉的浪潮中&#xff0c;时常能听到一些业界大佬发表关于财富积累的独到见解。 其中&#xff0c;有一种观点颇为引人注目&#xff0c;那便是“赚大钱比赚小钱容易”。 此言一出&#xf…