Spring 如何创建 Bean 实例的?

Spring 创建 Bean 实例的过程主要由 BeanFactory 接口及其实现类(通常是 AbstractBeanFactorydoGetBean 方法和 DefaultListableBeanFactorypreInstantiateSingletons 方法)负责。这个过程涉及多个步骤,包括 Bean 定义的解析、依赖的处理、实例化、属性填充、初始化等。

以下是 Spring 创建 Bean 实例的详细步骤:

1. 获取 Bean 定义 (Get BeanDefinition):

  • BeanDefinitionRegistry (通常是 DefaultListableBeanFactory 内部的 Map) 中根据 Bean 的名称获取对应的 BeanDefinition 对象。

2. 检查是否已创建 (Check if already created):

  • 单例 Bean (Singleton): 检查该 Bean 是否已经创建并缓存(在 singletonObjects 一级缓存中)。如果是,直接返回缓存的实例。
  • 原型 Bean (Prototype): 每次请求都会创建新的实例。
  • 其他作用域 (Request, Session, etc.): 根据具体的作用域规则进行检查。

3. 处理 depends-on (Handle depends-on):

  • 如果该 Bean 定义了 depends-on 属性(依赖于其他 Bean),则先递归地创建并初始化它所依赖的 Bean。

4. 创建 Bean 实例 (Create Bean Instance):

  • 选择创建方式: Spring 支持多种创建 Bean 实例的方式:

    • 构造函数 (Constructor): 使用 Bean 类的构造函数创建实例(最常见的方式)。
      • 无参构造函数: 如果没有指定构造函数参数,则使用无参构造函数。
      • 有参构造函数: 如果指定了构造函数参数,则使用匹配的构造函数。
        • 自动装配构造函数参数: 根据类型或名称自动解析构造函数参数。
        • 手动指定构造函数参数: 在 XML 配置或 Java 配置中显式指定构造函数参数。
    • 静态工厂方法 (Static Factory Method): 使用静态工厂方法创建实例。
      • 在 Bean 定义中指定 factory-method 属性,指向静态工厂方法。
      • 静态工厂方法必须返回 Bean 的实例。
    • 实例工厂方法 (Instance Factory Method): 使用实例工厂方法创建实例。
      • 在 Bean 定义中指定 factory-bean 属性,指向工厂 Bean。
      • 在 Bean 定义中指定 factory-method 属性,指向工厂 Bean 中的实例方法。
      • 实例工厂方法必须返回 Bean 的实例。
    • FactoryBean: 如果 Bean 本身是一个 FactoryBean,则调用其 getObject() 方法来获取实际的 Bean 实例。
      • FactoryBean 是一个特殊的 Bean,它可以创建和返回其他 Bean 的实例。
  • 实例化:

    • 反射 (Reflection): 通常情况下,Spring 使用 Java 反射机制(Constructor.newInstance()Method.invoke())调用构造函数或工厂方法来创建 Bean 实例。
    • CGLIB: 如果需要创建代理对象,Spring 可能会使用 CGLIB 动态生成子类。
    • InstantiationAwareBeanPostProcessor: 在 Bean 实例化前后,Spring 会调用 InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiationpostProcessAfterInstantiation 方法,允许对实例化过程进行干预(例如,返回一个代理对象而不是原始的 Bean 实例)。

5. 循环依赖处理 (早期暴露):

  • 如果是单例 Bean 且允许循环依赖, 则在实例化之后, 属性注入之前, 将创建 Bean 的 ObjectFactory 放入三级缓存 (singletonFactories), 以便其他 Bean 在创建过程中可以获取到该 Bean 的早期引用.

6. 属性填充 (Populate Bean):

  • 将 Bean 定义中指定的属性值设置到 Bean 实例中。
  • 注入方式:
    • Setter 注入: 调用 Bean 的 Setter 方法。
    • 字段注入: 直接设置 Bean 的字段值(不推荐)。
  • 属性解析:
    • 字面量值: 直接设置字符串、数字、布尔值等字面量值。
    • 引用其他 Bean: 根据 Bean 的名称或类型,从容器中获取依赖的 Bean,并注入。
      • 自动装配 (Autowiring): 根据类型 (byType)、名称 (byName) 或构造函数 (constructor) 自动解析和注入依赖。
      • 手动装配: 在 XML 配置或 Java 配置中显式指定依赖关系。
      • @Autowired@Resource@Value 等注解:AutowiredAnnotationBeanPostProcessor (实现了 InstantiationAwareBeanPostProcessor) 处理。
    • 集合、数组、Map: 解析配置中的集合、数组、Map 元素,并注入。
    • SpEL 表达式: 解析 SpEL 表达式,并将结果注入。
    • 占位符: 解析占位符(例如,${property.name}),并从属性源(PropertySource)中获取值。
  • 类型转换: 如果属性的类型与配置值的类型不匹配,Spring 会尝试进行类型转换(使用 TypeConverterConversionService 或自定义的 PropertyEditor)。
  • InstantiationAwareBeanPostProcessor.postProcessProperties/postProcessPropertyValues:
    • 在属性注入阶段, 会调用 InstantiationAwareBeanPostProcessorpostProcessProperties (或 postProcessPropertyValues, 已弃用) 方法.
    • 允许对属性值进行修改或执行其他操作.

7. Aware 接口回调:

  • 如果 Bean 实现了 Spring 提供的一些 Aware 接口,容器会在属性注入完成后、初始化之前调用这些接口的方法,将相应的资源注入到 Bean 中。
  • 常见的 Aware 接口:
    • BeanNameAware: 注入 Bean 的名称。
    • BeanFactoryAware: 注入 BeanFactory
    • ApplicationContextAware: 注入 ApplicationContext
    • EnvironmentAware: 注入 Environment
    • ResourceLoaderAware: 注入 ResourceLoader
    • MessageSourceAware: 注入 MessageSource
    • 其他…

8. 初始化 (Initialization):

  • BeanPostProcessor 前置处理:

    • 调用所有已注册的 BeanPostProcessorpostProcessBeforeInitialization 方法。
    • 允许在 Bean 初始化之前对 Bean 进行修改或执行其他操作(例如,AOP 代理就是在这里创建的)。
  • 调用初始化方法:

    • InitializingBean 接口: 如果 Bean 实现了 InitializingBean 接口,则调用其 afterPropertiesSet 方法。
    • @PostConstruct 注解: 如果 Bean 的方法上有 @PostConstruct 注解,则调用该方法。
    • init-method 属性: 如果 Bean 定义中指定了 init-method 属性,则调用指定的方法(通过反射)。
  • BeanPostProcessor 后置处理:

    • 调用所有已注册的 BeanPostProcessorpostProcessAfterInitialization 方法。
    • 允许在 Bean 初始化之后对 Bean 进行修改或执行其他操作。

9. 注册一次性 Bean (Register Disposable Bean):

  • 如果 Bean 实现了 DisposableBean 接口,或者定义了销毁方法(@PreDestroy 注解或 destroy-method 属性),则将该 Bean 注册为一次性 Bean,以便在容器关闭时销毁。

10. 完成 (Completion):

  • 对于单例 Bean,将创建好的 Bean 实例放入单例缓存中(singletonObjects 一级缓存)。
  • 对于原型 Bean,将创建好的 Bean 实例返回给调用者。

总结流程图:

+-----------------------+
|    getBean(name)     |  (获取 Bean)
+-----------------------+|V
+-----------------------+
|  Get BeanDefinition   |  (获取 Bean 定义)
+-----------------------+|V
+-----------------------+
| Check if created      |  (检查是否已创建)
+-----------------------+|V
+-----------------------+
| Handle depends-on     |  (处理 depends-on)
+-----------------------+|V
+-----------------------+
| Create Bean Instance  |  (创建 Bean 实例)
+-----------------------+||  - 选择创建方式:|    - 构造函数 (无参/有参, 自动装配/手动指定)|    - 静态工厂方法|    - 实例工厂方法|    - FactoryBean|  - 实例化:|    - 反射 (Constructor.newInstance() 或 Method.invoke())|    - CGLIB (如果需要创建代理)|  - InstantiationAwareBeanPostProcessor (before/after)|V
+---------------------------+
| Early Singleton Exposure  | (早期暴露, 处理循环依赖)
+---------------------------+|V
+-----------------------+
|   Populate Bean       |  (属性填充)
+-----------------------+||  - 注入方式:|    - Setter 注入|    - 字段注入|  - 属性解析:|    - 字面量值|    - 引用其他 Bean (自动装配/手动装配, @Autowired, @Resource, @Value)|    - 集合、数组、Map|    - SpEL 表达式|    - 占位符|  - 类型转换|  - InstantiationAwareBeanPostProcessor.postProcessProperties|V
+-----------------------+
|   Aware接口回调      |
+-----------------------+|V
+-----------------------+
|   Initialization      |  (初始化)
+-----------------------+||  - BeanPostProcessor (before)|  - InitializingBean.afterPropertiesSet|  - @PostConstruct|  - init-method|  - BeanPostProcessor (after)|V
+-----------------------+
|Register DisposableBean| (注册一次性 Bean)
+-----------------------+|V
+-----------------------+
|       Return Bean     |  (返回 Bean 实例)
+-----------------------+

关键点:

  • BeanFactory 是创建 Bean 实例的核心组件。
  • BeanDefinition 包含了创建 Bean 实例所需的所有信息。
  • Spring 支持多种创建 Bean 实例的方式(构造函数、工厂方法、FactoryBean)。
  • Spring 支持多种注入方式(Setter 注入、字段注入)。
  • InstantiationAwareBeanPostProcessor 可以在 Bean 实例化前后进行干预。
  • BeanPostProcessor 可以在 Bean 初始化前后进行处理(AOP 的关键)。
  • Aware 接口用于注入容器提供的资源。
  • Spring 使用三级缓存来解决单例 Bean 的循环依赖.

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

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

相关文章

第六:go 操作 redis-go

Redis 在项目开发中redis的使用也比较频繁,本文介绍了Go语言中go-redis库的基本使用。 Redis介绍 Redis是一个开源的内存数据库,Redis提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上。除此之外&am…

【RabbitMQ】RabbitMQ如何保证消息不丢失?

为了保证消息不丢失,需要在生产者、RabbitMQ本身和消费者三个环节采取相应措施。 1.生产者端:确保消息发送成功 1.1开启消息确认机制(Publisher Confirms) 原理: 生产者发送消息后,RabbitMQ会返回一个确认(ACK),表示消息已成功…

fastapi+angular外卖系统

说明: fastapiangular外卖系统 1.美食分类(粥,粉,面,炸鸡,炒菜,西餐,奶茶等等) 2.商家列表 (kfc,兰州拉面,湘菜馆,早餐店…

Kafka-Exporter 9308端口启用TLS认证的完整指南

#作者:张桐瑞 文章目录 1 方案描述2 涉及版本3 使用CA自签证书3.1一键生成证书脚本3.1.1证书脚本3.1.2执行结果 3.2分步自建证书过程3.2.1生成CA私钥3.2.2生成CA自签名证书3.2.3生成服务器私钥和证书申请文件CRS 3.3最终的文件列表 4 Exporter启动命令4.1参数说明 …

NFS共享搭建

准备工作 首先确保已经建了两台虚拟机,都是桥接模式,一台是windows server 2019 一台是centos7 用户配额教程,是在windows server 2019中,先新建虚拟池,然后创建虚拟磁盘,记得添加磁盘类型要选择第三个,要不…

DFT mode下hard phy STA Nopath

hard Phy boundary No Path 1. shift mode; shift cornor出现No Path的; PHY SI SO在shift mode必须有timing的path; 展示为No constrained path; check step: report_timing -though NO constrained path set timing_report_unconstrained true report again you will…

【工作记录】F12查看接口信息及postman中使用

可参考 详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)_f12查看接口及参数-CSDN博客 1、接口信息 接口基础知识2:http通信的组成_接口请求信息包括-CSDN博客 HTTP类型接口之请求&响应详解 - 三叔测试笔记…

《自然》:陆地蒸散量研究的统计失误被撤回-空间加权平均的计算方法

文章目录 前言一、空间加权平均的计算方法二、代码1.Python 实现2.MATLAB代码 前言 In this article, we calculated global land evapotranspiration for 2003 to 2019 using a mass-balance approach. To do this, we calculated evapotranspiration as the residual of the…

开源软件许可证冲突的原因和解决方法

1、什么是开源许可证以及许可证冲突产生的问题 开源软件许可证是一种法律文件,它规定了软件用户、分发者和修改者使用、复制、修改和分发开源软件的权利和义务。开源许可证是由软件的版权所有者(通常是开发者或开发团队)发布的,它…

【el-upload】el-upload组件 - list-type=“picture“ 时,文件预览展示优化

目录 问题图el-upload预览组件 PicturePreview效果展示 问题图 el-upload <el-uploadref"upload"multipledragaction"#":auto-upload"false":file-list"fileList"name"files":accept".png,.jpg,.jpeg,.JGP,.JPEG,.…

微前端 qiankun vite vue3

文章目录 简介主应用 qiankun-main vue3 vite子应用 qiankun-app-vue2 webpack5子应用 qiankun-react webpack5子应用 quankun-vue3 vite遇到的问题 简介 主要介绍以qiankun框架为基础&#xff0c;vite 搭建vue3 项目为主应用&#xff0c;wepack vue2 和 webpack react 搭建的…

C#从入门到精通(1)

目录 第一章 C#与VS介绍 第二章 第一个C#程序 &#xff08;1&#xff09;C#程序基本组成 1.命名空间 2.类 3.Main方法 4.注释 5.语句 6.标识符及关键字 &#xff08;2&#xff09;程序编写规范 1.代码编写规则 2.程序命名方法 3.元素命名规范 第三章 变量 &…

东隆科技携手PRIMES成立中国校准实验室,开启激光诊断高精度新时代

3月12日&#xff0c;上海慕尼黑光博会期间&#xff0c;东隆科技正式宣布与德国PRIMES共同成立“中国校准实验室”。这一重要合作标志着东隆科技在本地化服务领域的优势与PRIMES在激光光束诊断领域的顶尖技术深度融合&#xff0c;旨在为中国客户提供更快速、更高精度的服务以及本…

HarmonyOS Next~鸿蒙系统架构设计解析:分层、模块化与智慧分发的技术革新

HarmonyOS Next&#xff5e;鸿蒙系统架构设计解析&#xff1a;分层、模块化与智慧分发的技术革新 ​ ​ 鸿蒙操作系统&#xff08;HarmonyOS&#xff09;作为华为自主研发的分布式操作系统&#xff0c;其架构设计以全场景、多设备协同为核心目标&#xff0c;通过分层架构、模…

Vue Router工作原理探究

摘要&#xff1a; 随着单页应用&#xff08;SPA&#xff09;的广泛流行&#xff0c;路由系统成为前端开发中至关重要的部分。Vue Router作为Vue.js官方的路由管理器&#xff0c;为Vue应用提供了强大的路由功能。本文深入探讨Vue Router的工作原理&#xff0c;包括其核心概念、路…

SysOM 可观测体系建设(一):万字长文解读低开销、高精度性能剖析工具livetrace

可观测性是一种通过分析系统输出结果并推断和衡量系统内部状态的能力。谈及可观测性一般包含几大功能&#xff1a;监控指标、链路追踪、告警日志&#xff0c;及 Continues Profiling 持续剖析能力。对于操作系统可观测&#xff0c;监控指标可以帮助查看各个子系统&#xff08;I…

网络安全设备配置与管理-实验4-防火墙AAA服务配置

实验4-p118防火墙AAA服务配置 从这个实验开始&#xff0c;每一个实验都是长篇大论&#x1f613; 不过有好兄弟会替我出手 注意&#xff1a;1. gns3.exe必须以管理员身份打开&#xff0c;否则ping不通虚拟机。 win10虚拟机无法做本次实验&#xff0c;必须用学校给的虚拟机。首…

路由Vue Router基本用法

路由的作用是根据URL来匹配对应的组件&#xff0c;并且无刷新切换模板的内容。vue.js中&#xff0c;可使用Vue Router来管理路由&#xff0c;让构建单页应用更加简单。 一、效果 二、实现 1.项目中安装Vue Router插件 pnpm install vue-routerlastest 2.main.js import { …

24. 状态模式

原文地址: 状态模式 更多内容请关注&#xff1a;智想天开 1. 状态模式简介 状态模式&#xff08;State Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许一个对象在其内部状态改变时改变其行为&#xff0c;使得该对象看起来似乎修改了其类。状态模式通过将状态的行…

【Qt】Qt + Modbus 服务端学习笔记

《Qt Modbus 服务端学习笔记》 1.因为项目的需要&#xff0c;要写一个modbus通信&#xff0c;csdn上感觉有些回答&#xff0c;代码是人工智能生成的&#xff0c;有些细节不对。我这个经过实测&#xff0c;是可以直接用的。 首先要包含Qt 的相关模块 Qt Modbus 模块主要包含以…