当前位置: 首页 > news >正文

从根儿上学习spring 八 之run方法启动第四段(2)

图2

我们接着上一篇接着来看refresh方法,我们上一小节说完了invokeBeanFactoryPostProcessors(beanFactory)方法,这一节我们来看registerBeanPostProcessors(beanFactory)方法。

从方法名称定义我们就能看出这个方法主要是用来注册BeanPostProcesor的。我们之前说过BeanPostProcesor的作用是在bean的初始化过程中作为后置处理器来对bean进行各种操作的,所以在开始初始化bean之前需要把它们先找到并注册到spring容器中。

图2 -23行

我们接着看initMessageSource();方法,该方法是向spring容器里添加一个MessageSource接口,这个接口是一个策略接口,支持对message进行国际化和参数化配置。也就是通过该接口的getMessage方法获取到的string类型的message消息可以支持国际化配置和参数化配置。具体使用例子我这里就不展开了,我们主要还是关注spring的bean实例化及初始化过程吧。后面这些细节知识点我们都通过单独的专题文章来一一讲解。

图2-26行

initApplicationEventMulticaster();从该方法名称我们也可以猜出来这个方法是初始化一个ApplicationEventMulticaster对象到spring容器。那么该对象是干嘛的呢,它负责传播ApplicationEvent事件的,也就是当我们想想某类监听器发布一个事件时可以通过ApplicationEventMulticaster来实现。大概逻辑就是该对象里维护了spring容器内的所有监听器ApplicationListener,当你通过它来发布事件时,它会遍历所有的监听器并调用监听器的onApplicationEvent方法。是不是很简单,大家可以自己点进去看下这个类的代码、

图2-29行

onRefresh();该方法在不同的applicationContext子类有不同的实现,spring boot通过ServletWebServerApplicationContext的子类实现了tomcat容器的启动,大家感兴趣的可以自行看下,后面有时间也可以写篇单独的文章来看springboot和tomcat的结合及启动过程

图2-32行

registerListeners();方法我们从名字也能猜出个大概--注册ApplicationEvent事件的监听器,上面我们已经通过initApplicationEventMulticaster()方法注册了事件传播器,这里即将注册事件监听器,这样有了事件就可以正常传播及执行了。

图2-35行

finishBeanFactoryInitialization(beanFactory);从该方法的注释我们就可以知道,这个方法才是实例化并初始化我们写的所有对象的方法。我们跳开其他细节直接今日其调用的最核心的方法:DefaultListableBeanFactory#preInstantiateSingletons,下图3展示了该方法的核心代码。

图3

这部分代码一大串核心就是遍历所有的beanDefinitionNames集合,调用getBean(beanName)方法进行bean的实例化及初始化。

上面一大串都是处理FactoryBean的逻辑,不是我们讨论的重点。这里对FactoryBean做个简单的介绍。从名字看多少和BeanFactory有点像,正好把单词bean和factory给反过来了。BeanFactory是spring创建及维护所有bean的地方,而FactoryBean则可以理解为工厂模式,通过它可以生成一类对象。其最核心的方法是getObject()方法返回一个对象实例,比较典型的使用例子就是mybatis的mapper接口使用FactoryBean生成bean实例。后面我们讲bean的初始化过程还会讲到这里就先到这。接下来我们开始看getBean(beanName)方法。

图4

我们先看图4的242行的transformedBeanName(name)方法,在看这个方法逻辑前我们先看看图3的beanName是怎么来的?那故事还得回到spring扫描获取BeanDefinition的地方,这时spring就会为我们生成beanName,主要通过BeanNameGenerator#generateBeanName方法生成beanName。

主要逻辑是spring会先找@Component或者javax.inject.Named等注解,如果存在这些注解并且配置了value属性那么beanName就会使用这些注解的value属性,否则就会使用当前class类的ShortName并使首字母小写来作为beanName。

说完了beanName的来源,我们再来看看transformedBeanName(name)逻辑以及为什么要对参数name进行转换?其实主要是针对传入的是bean的别名和FactoryBean的name两种情况。如果是别名的话需要转换为真实的beanName,如果获取的bean是FactoryBean的话name前面会被额外拼接一个&符号,这个符号的作用只是告诉spring要获取的bean是FactoryBean本身而不是让FactoryBean管理的真实对象。这里大家可以看下图3的740行,传入的name就是在beanName前面拼接了&符号。

接着我们看图4-246行getSingleton(beanName)方法,该方法会调用getSingleton(String beanName, boolean allowEarlyReference)方法,第二个参数allowEarlyReference的意思是是否允许获取为初始化完成的实例,通过getSingleton(beanName)方法调用时默认为true。

图5

我们看下图5的getSingleton(String beanName, boolean allowEarlyReference)方法,该方法会先尝试从已完成初始化的容器singletonObjects中获取实例,如果获取的实例为空且isSingletonCurrentlyInCreation(beanName)方法返回true,则尝试从未完成初始化的容器earlySingletonObjects中获取实例。

这里的两个容器singletonObjects和earlySingletonObjects分别代表的是已经完成实例化和初始化的成熟bean和由于循环依赖而到这未完成初始化的提前暴露出去的bean。这里相信大家会有疑问,为什么在singletonObjects容器返回空时要调用isSingletonCurrentlyInCreation(beanName)方法方法true才能从earlySingletonObjects获取实例呢?

isSingletonCurrentlyInCreation(beanName)方法逻辑很简单就是判断beanName在不在singletonsCurrentlyInCreation集合里,而添加时机是在创建bean之前,在DefaultSingletonBeanRegistry#getSingleton(String,ObjectFactory)方法里。大家可以理解为如果这里isSingletonCurrentlyInCreation(beanName)方法返回true则表示当前beanName这个bean之前尝试创建过,后面被打断了现在又来尝试创建了,也就是出现了循环依赖了。

举个例子,有两个类分别是A和B,A依赖了B,B也依赖了A。假设spring先初始化A,这时候发现A依赖B所以在初始化A的过程中被打断跑去实例化并初始化B(注意这时候A的初始化过程被打断了),在初始化B的时候发现B又依赖A,spring又尝试去初始化A,这时候调用getSingleton(String beanName, boolean allowEarlyReference)方法时(beanName为A),isSingletonCurrentlyInCreation(beanName)方法就会返回true。

那么我们假设如果这里不调用isSingletonCurrentlyInCreation(beanName)方法行不行,我理解从业务逻辑上没什么影响但是影响性能,如果没有这个判断那么所有的bean初始化过程都会在这里获取锁singletonObjects进行阻塞并往下走到183行逻辑才退出,而有了这个判断为false表示是第一次创建该bean实例肯定不存在earlySingletonObject所以没必要获取锁往下走。

我们接着往下看,当this.earlySingletonObjects.get(beanName)方法返回的对象也为空时且allowEarlyReference为true则尝试从singletonFactories容器中获取beanName的SingletonFactory,该接口是单例工厂,只有一个getObject()方法。此时如果获取的singletonFactory不为空则使用该单例工厂获取bean实例并放到earlySingletonObjects容器中,并移除singletonObjects容器中的bean(其实此时该容器中一般不会有该beanName的值移除只是一种健全写法,毕竟已经通过单例工厂生成了新的实例)。

此时大家可能有两个疑问,该beanName的SingletonFactory是什么时候添加进去的? 为什么获取的object对象要放到earlySingletonObjects容器中而不是singletonFactories容器呢?带着疑问我们继续往下看。

说完图4的getSingleton(beanName);方法,我们继续回头看图4--doGetBean方法中的其他方法。

由于第一次执行getSingleton(beanName);方法肯定是null,所以执行else逻辑,为了故事的延续我们继续对doGetBean方法进行分析。为了不让篇幅过长接下来的分析我们下篇接着分析。

相关文章:

从根儿上学习spring 八 之run方法启动第四段(2)

图2 我们接着上一篇接着来看refresh方法,我们上一小节说完了invokeBeanFactoryPostProcessors(beanFactory)方法,这一节我们来看registerBeanPostProcessors(beanFactory)方法。 从方法名称定义我们就能看出这个方法主要是用来注册BeanPostProcesor的。…...

牛顿插值法代替泰勒公式

引入 例题 近似函数: 通过这个近似函数可以看出,若要证的函数超过二阶可导,那么就不适合用牛顿插值法代替泰勒公式 因为,后面的操作非常复杂,不划算了… 总结 我们可以通过牛顿插值法生成一个逼近曲线的直线&#xf…...

为 Laravel 提供生产模式下的容器化环境:打造现代开发环境的终极指南

为 Laravel 提供生产模式下的容器化环境:打造现代开发环境的终极指南 在现代开发中,容器化已经成为一种趋势。使用 Docker 可以让我们轻松地管理和部署应用程序。本文将带你一步步构建一个高效的 Laravel 容器化环境,确保你的应用程序在开发…...

Visual Studio 和 VSCode 哪个好?

​ 您好,我是程序员小羊! 前言 想要对Visual Studio 和 VSCode 进行比较,就要充分了解Visual Studio (VS) 和 Visual Studio Code (VSCode) 各有其优势和适用场景进行分析。Visual Studio (VS) 和 Visual Studio Code (VSCode) 都是由微软开发…...

百款精选的HTML5小游戏源码,你可以下载并直接运行在你的小程序或者自己的网站上

今天我带来了一份特别的礼物——百款精选的HTML5小游戏源码,你可以下载并直接运行在你的小程序或者自己的网站上,只需双击index.html即可开始。无论你是在寻找创意引流,还是想为你的网站增添互动性,这些小游戏都能帮你实现&#x…...

01 LVS负载均衡群集

集群 在互联网应用中,随着站点对硬件的性能、响应速度、服务稳定性、数据可靠性等要求越来越高,单台服务器越来越力不从心 集群的含义 Cluster,集群也叫群集由多台主机构成,但对外只表现为一个整体 集群分类 类型 负载均衡集…...

Redis结合Lua脚本的简单使用

我们就拿购物车举例子 现在有5个东西免费送&#xff0c;我们只能选择1个 例如 可乐 美年达 香蕉 苹果 薯片 我们选择后就放进redis里面 然后我们不能选重复&#xff0c;只能选不同 Lua脚本 我们redis使用lua脚本的时候&#xff0c;会传两个参数进去 一个是List<Strin…...

Java使用zip4j加密压缩和解压文件与文件夹

最近项目中有个需求需要对文件夹进行压缩后传输&#xff0c;考虑数据泄露安全性问题&#xff0c;需要对压缩包进行加密&#xff0c;特地查找了下开源压缩加密类库&#xff0c;找到了Java语言开发的zip4j库&#xff0c;觉得挺好用的&#xff0c;在这分享给大家&#xff01; Jav…...

一款好用的开源网站内容管理系统

今天给大家介绍的是一款开源网站内容管理系统&#xff08;灵活、易用&#xff0c;性能良好、运行稳定&#xff0c;轻松管理建设网站&#xff09; 官网&#xff1a;https://www.ujcms.com/ 介绍 客户端兼容Edge&#xff08;Chromium版&#xff09;、谷歌浏览器&#xff08;Chro…...

Qt Modbus 寄存器读写实例

一.线圈状态寄存器读写 项目效果如下 1. 写单个寄存器 MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status); int addrui->spinBoxwirte_addr->value();int dataui->spinBoxwirte_data->value();int ret modbus_write_bit(mb,addr,d…...

centos安装es、kibana、ik

这里es使用的是7.10.2版本的es&#xff0c;物料包下载地址如下 #注意安装的插件需和es版本保持一致 #es https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.2-linux-x86_64.tar.gz #kibana https://artifacts.elastic.co/downloads/kibana/kibana-7.10…...

调试工具之GDB的基本使用

GDB基本使用 GDB是Linux下一款非常强大的调试软件&#xff0c;其实就是GNU Debugger的缩写。接下来我们学习一下他的基本使用。 例子函数&#xff0c;其中只有一个ds18b20的采集温度函数和一个主函数&#xff1a; #include <stdio.h> #include <errno.h> #includ…...

C++ //练习 16.14 编写Screen类模板,用非类型参数定义Screen的高和宽。

C Primer&#xff08;第5版&#xff09; 练习 16.14 练习 16.14 编写Screen类模板&#xff0c;用非类型参数定义Screen的高和宽。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 template <int H, int W> class Screen{…...

【Java】深度解析监视器的组成原理

目录 一、什么是监视器&#xff08;Monitor&#xff09;二、监视器的组成部分三、线程的状态转换四、总结 一、什么是监视器&#xff08;Monitor&#xff09; 在Java中&#xff0c;监视器&#xff08;Monitor&#xff09;是用来实现线程同步的一种机制。每个Java对象都有一个与…...

Day14-Servlet后端验证码的实现

图片验证码的生成采用的是Kaptcha&#xff1b; Kaptcha是一个高度可配置的验证码生成工具&#xff0c;由Google开源。它通过一系列配置文件和插件&#xff0c;实现了将验证码字符串自动转换成图片流&#xff0c;并可以与session进行关联&#xff0c;从而在验证过程中使用&#…...

MySQL:数据库权限与角色

权限 MySQL 的权限管理系统是保障数据库安全性的关键组件之一。它允许数据库管理员精确控制哪些用户可以对哪些数据库对象执行哪些操作。 自主存取控制 DAC&#xff08;DiscretionaryAccess Control)&#xff1a;用户对于不同的数据库对象有不同的存取权限&#xff0c;不同的…...

等保测评练习卷25

等级保护初级测评师试题25 姓名&#xff1a; 成绩&#xff1a; 一、判断题&#xff08;10110分&#xff09; 1.安全区域边界对象主要根据系统中网络访问控制设备的部署情况来确定&#xff08;&#xff09;不是网络访问控制设备而…...

《python语言程序设计》2018第6章第28题 掷骰子 两个色子,分别是1到6

2、3、12 玩家输 7、11玩家赢 4、5、6、8、9、10算1点&#xff0c;之后出7玩家输或者和上一次相同。def rolled(num_t):count 0still_win 0second_win 0still_lose 0second_lose 0while count < num_t:a_1 random.randint(1, 6)b_1 random.randint(1, 6)tTen a_1 b…...

Java方法递归

目录 1.方法递归调用 基本介绍 递归能解决什么问题&#xff1f; 八皇后问题 递归举例 递归重要规则 练习 2.递归调用应用实例-迷宫问题 3.递归调用实例-汉诺塔 4.递归调用实例-八皇后问题 1.方法递归调用 基本介绍 简单来说&#xff0c;递归就是自己调用自己。 …...

目标跟踪那些事

目标跟踪那些事 跟踪与检测的区别 目标跟踪和目标检测是计算机视觉中的两个重要概念&#xff0c;但它们的目的和方法是不同的。 目标检测(object Detection)&#xff1a;是指在图像或视频帧中识别并定位一个或多个感兴趣的目标对象的过程 。 目标跟踪(object Tracking)&…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...