Spring源码分析:创建 BeanDefinition 流程

news2025/7/28 0:19:23

一、前期准备

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

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

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

相关文章

CentOs8 安装Jenkins一系列问题总结

CentOs8 安装 Jenkins 总结 文章目录CentOs8 安装 Jenkins 总结一、版本&安装二、Jenkins配置1. 配置 Java 路径2. 配置用户名称(一定要改成root&#xff01;&#xff01;&#xff01;)3. 启动 &停止& 重启 Jenkins 命令1. 启动2. 停止3. 重启三、成功四、问题记录…

同事每天早下班,原来是用了这8个开发工具

引言 工欲善其事必先利其器&#xff0c;说的就是工匠要想更加高效的做事情&#xff0c;就得先将工具变得锋利。那么对于程序员来说同样也是如此&#xff0c;如果要想每天早点下班&#xff0c;就必须借助于一些开发工具来提高自己的工作效率&#xff0c;今天慕枫就给大家总结一…

【手撕源码】vue2.x双向数据绑定原理

&#x1f431; 个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️ 作者简介&#xff1a;前端领域新星创作者、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff1a;vue3从入门…

Teradata在华落幕,国产化崛起,袋鼠云数栈会是更好的选择吗?

2月15日&#xff0c;数仓软件巨头Teradata宣布根据其对中国当前和未来商业环境的慎重评估&#xff0c;将逐步结束在中国的直接运营&#xff0c;后续进入中国公司的关闭程序。 一石激起千层浪&#xff0c;这一消息&#xff0c;在国内的To B市场引起了广泛关注。Teradata这家进入…

mongoDB的安装与使用

MongoDB安装MongoDB官方网站&#xff1a;https://www.mongodb.com/try/download/community-kubernetes-operator2软件安装权限不足&#xff1a;https://www.javaclub.cn/database/56541.htmlstep1:打开安装包直接点击Nextstep2&#xff1a;继续点击Nextstep3&#xff1a;点击自…

Oracle 12C以上统计信息收集CDB、PDB执行时间不一致问题

文章目录前言一、统计信息窗口期调查二、时区调查三、查询alert记录四、why Database Statistic Collection Job is running two times inside a Maintenance Window?五、Default Scheduler Timezone Value In PDB$SEED Different Than CDB六、总结前言 在实际工作中发现一个…

Tina_Linux_功耗管理_开发指南

Tina Linux 功耗管理开发指南 1 概述 1.1 编写目的 简要介绍tina 平台功耗管理机制&#xff0c;为关注功耗的开发者&#xff0c;维护者和测试者提供使用和配置参考。 1.2 适用范围 表1-1: 适用产品列表产品名称内核版本休眠类型参与功耗管理的协处理器R328Linux-4.9NormalS…

ESP32设备驱动-MLX90393磁场传感器驱动

MLX90393磁场传感器驱动 文章目录 MLX90393磁场传感器驱动1、MLX90393介绍2、硬件准备3、软件准备4、驱动实现1、MLX90393介绍 MLX90393 磁场传感器可以在运行时重新编程为不同的模式和不同的设置。 该传感器使用 Melexis 专有的 Triaxis 技术提供与沿 XYZ 轴感应的磁通密度成…

Matplotlib之画图模块

目录 matplotlib简介 条形图 折线图 散点图 matplotlib简介 Matplotlib 是 Python 的绘图库&#xff0c;它能让使用者很轻松地将数据图形化&#xff0c;并且提供多样化的输出格式。 Matplotlib 可以用来绘制各种静态&#xff0c;动态&#xff0c;交互式的图表。 Matplotli…

OpenCV-PyQT项目实战(9)项目案例04:视频播放

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列&#xff0c;持续更新中 OpenCV-PyQT项目实战&#xff08;1&#xff09;安装与环境配置 OpenCV-PyQT项目实战&#xff08;2&#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战&#xff08;3&#xff09;信号与槽机制 …

mars3d对geojson图层分属性设置样式

开发中可能会遇到如下需求&#xff0c;在全省的数据中按某个属性⾼亮展示某市区。此时就需要使⽤分属性样式的api了。⽂档如下。GeoJsonLayer - Mars3D API文档属性是根据⽮量数据的属性进⾏匹配。可以通过 layer.graphics[0]?.attr ⽅式获取。 指导有哪些属性之后先设置…

Spark3 新特性之AQE

文章目录Spark3 AQE一、 背景二、 Spark 为什么需要AQE? (Why)三、 AQE 到底是什么&#xff1f;(What)四、AQE怎么用&#xff1f;(How)4.1 自动分区合并4.2 自动数据倾斜处理4.3 Join 策略调整五、对比验证5.1 执行耗时5.2 自动分区合并5.3 自动数据倾斜处理六、结论Spark3 AQ…

电脑录屏怎么操作,操作步骤详解,2023新版

在日常的学习、生活和工作中&#xff0c;当小伙伴想要分享一段游戏视频或者教学视频时&#xff0c;电脑录屏就显得尤为重要了。但是小伙伴你是否知道电脑录屏怎么操作&#xff1f;今天小编就分享电脑录屏操作步骤的详细教程&#xff0c;一起来看看吧。 电脑录屏怎么操作1&#…

【剑指Offer】重建二叉树(递归+迭代)

重建二叉树一、递归法二、迭代法题目链接 题目描述&#xff1a; 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例 1: Input: preorder [3,9,20,15,7], inorder [9,3,15,…

C进阶:7.程序环境和预处理

目录 1.程序的翻译环境和执行环境 2.详解编译 链接 2.1翻译环境 2.2编译本身也分为几个阶段&#xff1a; 2.3运行环境 3.预处理详解 3.1预定义符号 3.2 #define 3.2.1 #define 定义标识符 3.2.2 #define 定义宏 3.2.3 #define 替换规则 3.2.4 # 和 ## 3.2.5带副…

大规模食品图像识别:T-PAMI 2023论文解读

美团基础研发平台视觉智能部与中科院计算所展开科研课题合作&#xff0c;共同构建大规模数据集Food2K&#xff0c;并提出渐进式区域增强网络用于食品图像识别&#xff0c;相关研究成果已发表于T-PAMI 2023。本文主要介绍了数据集特点、方法设计、性能对比&#xff0c;以及基于该…

Unreal Engine 虚幻引擎,性能分析,优化(二)

一、CPU 性能分析 如渲染线程中出现 CPU 受限&#xff0c;原因可能是绘制调用过多。这是一个常见问题&#xff0c;美术师通常会将绘制调用进行组合&#xff0c;从而减少消耗&#xff08;如&#xff1a;将多个墙壁组合为一个网格体&#xff09;。实际消耗存在于多个区域中&…

Ubuntu 22.04.2 发布,可升级至 Linux Kernel 5.19

Ubuntu 22.04 LTS (Jammy Jellyfish) Ubuntu 22.04.2 发布&#xff0c;可升级至 Linux Kernel 5.19 请访问原文链接&#xff1a;Ubuntu 22.04 LTS (Jammy Jellyfish)&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org 发行说…

file_get_contents 打开本地文件报错: failed to open stream: No such file or directory

php 使用file_get_contents时报错 failed to open stream: No such file or directory (打开流失败&#xff0c;没有这样的文件或目录) 1. 首先确保文件路径没问题 最好是直接复制一下文件的路径 2. windows电脑可以右键该文件 → 属性→安全 →对象名称 选中后复制一下 3. 然后…

【数据存储】浮点型在内存中的存储

目录 一、存储现象 二、IEEE标准规范 1.存储 2.读取 三、举例验证 1.存储 2.读取 浮点型存储的标准是IEEE&#xff08;电气电子工程师学会&#xff09;754制定的。 一、存储现象 浮点数由于其有小数点的特殊性&#xff0c;有很多浮点数是不能精确存储的&#xff0c;如&#…