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

Spring源码分析:创建 BeanDefinition 流程

一、前期准备

1.1 环境依赖

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.7.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.7.RELEASE</version></dependency>
</dependencies>

1.2 实体类

简单的User类,在测试过程中创建这个User类的对象。

public class User {private Integer id;private String name;public User() {System.out.println("创建了");}
}

1.3 applicationContext.xml

在applicationContext.xml配置bean对象。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.zqc.domain.User" id="user"></bean>
</beans>

1.4 测试代码

通过applicationContext.xml配置应用程序的上下文,在容器中创建User对象

public class SpringDemo {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");User user = (User) context.getBean("user");}
}

二、探究过程

2.1 目标

目标:BeanDefinition是什么?是什么时候创建的?

2.2 BeanDefinition的创建过程

2.2.1 回顾bean对象的创建

前面在分析Bean创建的过程中,发现在执行完refresh()方法后就完成了bean对象的创建。

在测试代码中创建context对象:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

ClassPathXmlApplicationContext构造器中调用了另一个构造器:

该构造器中执行了refresh()方法

在refresh()方法中创建了非懒加载的单例对象:

所以BeanDefinition可定在这行代码之前创建的。下面看看在refresh()方法的什么地方创建了BeanDefinition。

2.2.2 AbstractApplicationContext

🔶 refresh()方法

首先我们要知道,Bean对象和BeanDefinition对象都是是通过BeanFactory创建。

所以,只有在获取BeanFactory之后才能获取到BeanDefinition。

在这一行创建了beanFactory对象

查看一下beanFactory,找寻与BeanDefinition相关的属性: beanDefinitionMapbeanDefinitionNames

Spring源码分析:创建 BeanDefinition 流程

本文来和大家一起聊聊:Spring创建BeanDefinition流程

参考视频:https://www.bilibili.com/video/BV1Bq4y1Q7GZ?p=4

通过视频的学习和自身的理解整理出的笔记。

一、前期准备

1.1 环境依赖

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.7.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.7.RELEASE</version></dependency>
</dependencies>

1.2 实体类

简单的User类,在测试过程中创建这个User类的对象。

public class User {private Integer id;private String name;public User() {System.out.println("创建了");}
}

1.3 applicationContext.xml

在applicationContext.xml配置bean对象。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.zqc.domain.User" id="user"></bean>
</beans>

1.4 测试代码

通过applicationContext.xml配置应用程序的上下文,在容器中创建User对象。

public class SpringDemo {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");User user = (User) context.getBean("user");}
}

二、探究过程

2.1 目标

目标:BeanDefinition是什么?是什么时候创建的?

2.2 BeanDefinition的创建过程

2.2.1 回顾bean对象的创建

前面在分析Bean创建的过程中,发现在执行完refresh()方法后就完成了bean对象的创建。

在测试代码中创建context对象:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

ClassPathXmlApplicationContext构造器中调用了另一个构造器:

该构造器中执行了refresh()方法

在refresh()方法中创建了非懒加载的单例对象:

所以BeanDefinition可定在这行代码之前创建的。下面看看在refresh()方法的什么地方创建了BeanDefinition。

2.2.2 AbstractApplicationContext

🔶 refresh()方法

首先我们要知道,Bean对象和BeanDefinition对象都是是通过BeanFactory创建。

所以,只有在获取BeanFactory之后才能获取到BeanDefinition。

在这一行创建了beanFactory对象。

查看一下beanFactory,找寻与BeanDefinition相关的属性: beanDefinitionMapbeanDefinitionNames

🔹 beanDefinitionMap

key:bean的名称

value:beanDefinition,描述bean的相关信息

🔹 beanDefinitionNames:beanDefination的名称

说明当ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()执行完毕后,BeanDefination就已经创建完毕了。

obtainFreshBeanFactory()方法

refreshBeanFactory()方法

通过这行代码loadBeanDefinitions(beanFactory)创建了BeanDefinition对象。

2.2.3 AbstractXmlApplicationContext

loadBeanDefinitions()方法,输入beanFactory

通过读取xml文件来创建BeanDefinitions

beanFactory就是XmlBeanDefinitionReader里面的registry,所以后面我们看到的registry就是beanFactory对象。

loadBeanDefinitions()方法,输入beanDefinitionReader

方法重载,上面的形参类型为DefaultListableBeanFactory,这里的形参beanDefinitionReader,就是上面的beanFactory。

loadBeanDefinitions()方法,输入locations

loadBeanDefinitions(location)方法里创建了BeanDefinition。

2.2.4 AbstractBeanDefinitionReader

loadBeanDefinitions()方法,输入locations

loadBeanDefinitions()方法,输入locationsSet<Resource>

loadBeanDefinitions()方法,输入可变参数resources

2.2.5 XmlBeanDefinitionReader loadBeanDefinitions()方法,输入resources

loadBeanDefinitions()方法

doLoadBeanDefinitions()方法

registerBeanDefinitions()方法

2.2.6 DefaultBeanDefinitionDocumentReader

registerBeanDefinitions()方法

doRegisterBeanDefinitions()方法

parseBeanDefinitions()方法

这里通过解析xml文件遍历里面的bean标签创建beanDefinition

parseDefaultElement()方法

根据当前的元素标签,选择不同的解析方式。比如:import、alias、beans

processBeanDefinition()方法

在这里创建beanDefinition对象并存储在bdHolder中:

2.2.7 BeanDefinitionParserDelegate

parseBeanDefinitionElement()方法

parseBeanDefinitionElement()方法

parseBeanDefinitionElement()方法

创建BeanDefinition对象后,继续对xml文件进行解析并设置beanDefinition。

下面继续简单看看createBeanDefinition的过程。

createBeanDefinition()方法

2.2.8 BeanDefinitionReaderUtils

createBeanDefinition()方法

2.2.9 结论

在容器创建时会先去创建一个beanFactory,然后使用XmlBeanDefinitionReader去读取xml配置文件,把里面的标签进行解析,然后创建BeanDefinition对象来存放bean标签中各个属性的值。所以BeanDefinition相当于就是保存了bean的定义信息的对象。

通过BeanDefinition里面的信息,就可以使用反射来创建bean对象。

2.3 BeanDefinition的存储

2.3.1 DefaultBeanDefinitionDocumentReader

我们回到【2.2.6】节的DefaultBeanDefinitionDocumentReader的processBeanDefinition()方法中。

在这里创建beanDefinition对象并存储在bdHolder中。

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

那么接下来应该将bdHolder保存下来。

可以看出来getReaderContext().getRegistry()这就是一个beanFactory对象

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

这段代码的作用就是将beanDefintion对象注册到beanFactory中。

下面我们看看registerBeanDefinition()方法。

2.3.2 BeanDefinitionReaderUtils

下面看看registerBeanDefinition()方法。

2.3.3 DefaultListableBeanFactory

最终会运行到这里:

2.3.4 结论

BeanDefinition被创建后会被存入beanDefinitionMap集合和beanDefinitionNames集合中。

  • beanDefinitionMap:key为beanName,value为beanDefinition

  • beanDefinitionNames:存储beanName

相关文章:

Spring源码分析:创建 BeanDefinition 流程

一、前期准备1.1 环境依赖<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.7.RELEASE</version></dependency><dependency><groupId&…...

Linux 练习一(思维导图 + 练习过程)

文章目录一、Linux 用户管理及文件操作第一段练习记录&#xff1a;主要对用户进行删除添加设置密码等操作第二段练习记录&#xff1a;主要包括权限设置和查找命令第三段练习记录&#xff1a;关于文件的命令练习第四段练习记录&#xff1a;查找命令及查看内存命令的使用二、Linu…...

高德地图基础教程超详细版

在当前社会&#xff0c;对于地图的使用是很必须的&#xff0c;所以对于程序员来说也是需要掌握的技能&#xff0c;目前主流的又百度地图和高德地图&#xff0c;但是我建议使用高德地图&#xff0c;因为百度地图的API着实不好用吖&#xff0c;不好理解&#xff0c;对于开发人员来…...

基于A7核开发板的串口实现控制LED亮灭

1.通过操作Cortex-A7核&#xff0c;串口输入相应的命令&#xff0c;控制LED灯进行工作 1>例如在串口输入led1on,开饭led1灯点亮 2>例如在串口输入led1off,开饭led1灯熄灭 3>例如在串口输入led2on,开饭led2灯点亮 4>例如在串口输入led2off,开饭led2灯熄灭 5>例如…...

HyperGBM用Adversarial Validation解决数据漂移问题

本文作者&#xff1a;杨健&#xff0c;九章云极 DataCanvas 主任架构师 数据漂移问题近年在机器学习领域来越来越得到关注&#xff0c;成为机器学习模型在实际投产中面对的一个主要挑战。当数据的分布随着时间推移逐渐发生变化&#xff0c;需要预测的数据和用于训练的数据分布…...

关基系统三月重保安全监测怎么做?ScanV提供纯干货!

三月重保当前&#xff0c;以政府、大型国企央企、能源、金融等重要行业和领域为代表的关键信息基础设施运营单位都将迎来“网络安全大考”。 对重要关基系统进行安全风险监测并收敛暴露面&#xff0c;响应监管要求进行安全加固&#xff0c;重保期间实时安全监测与数据汇报等具体…...

RK3588关键电路 PCB Layout设计指南

1、音频接口电路 PCB 设计&#xff08;1&#xff09;所有 CLK 信号建议串接 22ohm 电阻&#xff0c;并靠近 RK3588 放置&#xff0c;提高信号质量&#xff1b;&#xff08;2&#xff09;所有 CLK 信号走线不得挨在一起&#xff0c;避免串扰&#xff1b;需要独立包地&#xff0c…...

二分边界详细总结

一、查找精确值 从一个有序数组中找到一个符合要求的精确值&#xff08;如猜数游戏&#xff09;。如查找值为Key的元素下标&#xff0c;不存在返回-1。 //这里是left<right。 //考虑这种情况&#xff1a;如果最后剩下A[i]和A[i1]&#xff08;这也是最容易导致导致死循环的…...

STM32---备份寄存器BKP和 FLASH学习使用

BKP库函数 学习BKP&#xff0c;首先就是知道BKP每一个函数的作用然后如何使用即可 使用备份域的作用只需要操作上面的两个函数即可&#xff0c;其余的都是它的其他功能 BKP简介 备份寄存器是42个16位的寄存器&#xff0c;可用来存储84个字节的用户应用程序数据。他们处在备份…...

Python-生成元组和字典

1.生成元组元组是元素按顺序组合后的产物&#xff0c;元组对象的类型是tuple型含有两个元素的元组成为数据对元组可以包含任意数量和任意类型的元素&#xff0c;其元素总数可以为0、1、2等&#xff0c;并且元素的先后顺序是由意义的。另外&#xff0c;元组中的元素类型没有必要…...

I.MX6ULL内核开发10:设备树

目录 一、设备树简介 二、设备树源码 三、获取设备树信息 1、增加设备节点 2、内核编译设备树 3、替换设备树文件 4、查看设备树节点 5、在驱动中获取节点的属性 6、编译驱动模块 7、加载模块 一、设备树简介 设备树的作用是描述一个硬件平台的硬件资源。这个“设备树…...

【大数据】记一次hadoop集群missing block问题排查和数据恢复

问题描述 集群环境总共有2个NN节点&#xff0c;3个JN节点&#xff0c;40个DN节点&#xff0c;基于hadoop-3.3.1的版本。集群采用的双副本&#xff0c;未使用ec纠删码。 问题如下&#xff1a; bin/hdfs fsck -list-corruptfileblocks / The list of corrupt files under path…...

国产音质好的蓝牙耳机有哪些?国产音质最好的耳机排行

随着时间的推移&#xff0c;真无线蓝牙耳机逐渐占据耳机市场的份额&#xff0c;成为人们日常生活中必备的数码产品之一。蓝牙耳机品牌也多得数不胜数&#xff0c;哪些国产蓝牙耳机音质好&#xff1f;下面&#xff0c;我们从音质出来&#xff0c;来给大家介绍几款国产蓝牙耳机&a…...

CTFer成长之路之XSS的魔力

XSS的魔力CTF XSS闯关 题目描述: 你能否过关斩将解决所有XSS问题最终获得flag呢&#xff1f; docker-compose.yml version: "3.2"services:xss:image: registry.cn-hangzhou.aliyuncs.com/n1book/web-xss:latestports:- 3000:3000启动方式 docker-compose up -…...

行锁、表锁、主键外键、表之间的关联关系

Java知识点总结&#xff1a;想看的可以从这里进入 目录2.4、行锁、表锁2.5、主键、外键2.5.1、主键2.5.2、外键2.6、表的关联关系2.4、行锁、表锁 MyISAM默认采用表级锁&#xff0c;InnoDB默认采用行级锁。 表锁&#xff1a;开销小&#xff0c;加锁快&#xff0c;不会出现死锁…...

JavaScript 进阶(面试必备)--charater4

文章目录前言一、深浅拷贝:one: 浅拷贝:two:深拷贝二、异常处理:one: throw 抛异常:two: try /catch 捕获异常:three:debugger三、处理thisthis指向 :one:普通函数this指向this指向 :two: 箭头函数this指向3.2 改变this:one: call():two: apply():three: bind()四、性能优化:on…...

ARM+FPGA架构开发板PCIE2SCREEN示例分析与测试-米尔MYD-JX8MMA7

本篇测评由电子发烧友的优秀测评者“zealsoft”提供。 本次测试内容为米尔MYD-JX8MMA7开发板其ARM端的测试例程pcie2screen并介绍一下FPGA端程序的修改。 ​ 01. 测试例程pcie2screen 例程pcie2screen是配合MYD-JX8MMA7开发板所带的MYIR_PCIE_5T_CMOS 工程的测试例&#…...

51单片机入门 - SDCC / Keil_C51 会让没有调用的函数参与编译吗?

Small Device C Compiler&#xff08;SDCC&#xff09;是一款免费 C 编译器&#xff0c;适用于 8 位微控制器。 不想看测试过程的话可以直接划到最下面看结论&#xff1a;&#xff09; 关于软硬件环境的信息&#xff1a; Windows 10STC89C52RCSDCC &#xff08;构建HEX文件&…...

OpenCV只含基本图像模块编译

编译OpenCV4.5.5只含基本图像模块&#xff0c;环境为Windows10 x64CMake3.23.3VS2019。默认编译选项编译得到的OpenCV库往往大几百MB甚至上GB&#xff0c;本文配置下编译得到的库压缩后得到的zip包大小仅6.25MB&#xff0c;适合使用OpenCV基本图像功能模块的项目移植而不牵涉其…...

Java实现阴历日历表(附带星座)

准备工作 1.无敌外挂(GitHub直达源码) Nobb 直击灵魂 https://github.com/xuyishanBD/Java_create_calendar.git2.maven配置(如果没有走上面的捷径) <dependencies><dependency><groupId>net.sourceforge.javacsv</groupId><artifactId>javac…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

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

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