Spring之IoC源码分析及设计思想(一)——BeanFactory

关于Spring的IOC

Spring 是一个开源的 Java 平台,它提供了一种简化应用程序开发的框架。它是一个分层的框架,包括两个主要的内核:控制反转(IOC)和面向切面编程(AOP)。IOC 允许应用程序将组件之间的依赖关系交给框架来管理,从而实现松耦合;而 AOP 则允许应用程序以声明式的方式实现横切关注点,如日志、事务、安全等。

Spring 的 IOC(Inversion of Control)是其核心特性之一,它允许应用程序将组件之间的依赖关系交给框架来管理,从而实现松耦合。 在传统的程序设计中,对象之间的依赖关系是由程序代码直接控制的,而在 IOC 的思想下,对象之间的依赖关系是由 Spring 容器控制的,程序代码只需要声明依赖关系,而不需要直接创建或管理对象。换言之,当我们通过配置声明好对象之间的依赖后,Spring容器会根据我们的配置帮我们创建对象实例并完成对象中各个成员变量的装配,而不需要我们手动创建或者查找各个对象实例来进行组装。我们可以认为IOC与JNDI相反——后者从容器中主动查找依赖(所需要的对象),而前者在容器初始化某个对象时不等对象请求就主动将依赖传递给它。

IOC的底层采用了工厂模式,所有的Bean(对象实例)都将由BeanFactory也就是Bean工厂来完成实例化,且实例化后理论上都需要被注册到容器中,由容器负责Bean的生命周期的管理(Bean的创建、依赖装配、初始化、销毁)。 开发者只需要按照Spring约定好的方式提供Bean的定义信息(主要以XML配置和注解配置为主,有时候也可以在运行期间通过某些方式实时提供)即可,Bean工厂会根据这些Bean定义来完成Bean的生成。因此,对Bean工厂的认识与理解正是认识SpringIOC的关键(Bean工厂是SpringIOC的逻辑实现)。

从片面的角度上来说,我们可以认为Spring就是一个针对Bean生命周期进行管理的容器。

关于BeanFactory

前面提到Bean工厂是SpringIOC的逻辑实现,因此正确理解Bean工厂正是认识SpringIOC的关键(这里的Bean工厂并不指的是BeanFactory接口,而是包含BeanFactory接口在内的一整套类与接口的实现)。下图是Bean工厂的实现类图:
Bean工厂的实现类图
从整个类图来看,我们可以发现所有的接口与类最终汇聚到了DefaultListableBeanFactory上了。DefaultListableBeanFactory这个类包含了SpringIOC完整的逻辑实现,是Spring默认的BeanFactory实现。事实上,在我们使用Spring时最熟悉的ClassPathXmlApplicationContext与FileSystemXmlApplicationContext两个类都是通过DefaultListableBeanFactory来实现SpringIOC的功能。具体源码可见下图:

ApplicationContext的getBean逻辑
在图中我们可以看到ApplicationContext的getBean逻辑正是调用了DefaultListableBeanFactory来实现的Bean的获取。其中AbstractApplicationContext正是前面提到的ClassPathXmlApplicationContext与FileSystemXmlApplicationContext的高层父类。

因此,我们对于SpringIOC的源码和分析只需要局限于DefaultListableBeanFactory即可。DefaultListableBeanFactory已经封装了SpringIOC中对Bean操作的完整逻辑。从前面第一张图(Bean工厂的实现类图)可以看到,在DefaultListableBeanFactory之上有着大量的接口和类,组成了非常复杂的类继承结构。但是其中最顶层的接口就只有BeanFactory、AliasRegistry以及SingletonBeanRegistry。三者分别赋予了Bean工厂不同的能力。而从DefaultListableBeanFactory的类名来看,也可以发现Spring对它的定义就是一个BeanFactory。本文主要讨论BeanFactory接口在SpringIOC设计中所承担的职责与角色,而不着重于类图中其他类与接口的能力

BeanFactory接口

BeanFactory接口是Spring定义的顶层接口,被定义为是Bean容器的客户端视图。即我们对Bean容器中Bean的获取可以通过BeanFactory接口来实现,而不需要关心其获取逻辑。换句话说,BeanFactory接口赋予了Bean容器向外提供Bean的能力。下图是BeanFactory接口中定义的方法列表:
BeanFactory接口结构
从图中看,我们能够发现BeanFactory接口中差不多有近一半的方法都是以getBean为名通过Bean名称、Bean类型去获取符合条件的Bean实例。至于剩下的基本也都是与Bean及其特性相关的操作,比如是否包含Bean、判断Bean是单例Bean还是原型Bean、类型是否匹配、获取Bean的类型和别名等。

因此,我们也能够确认BeanFactory接口确实与之前所说一致,是一个被设计用来访问Bean容器中Bean实例的客户端视图,定义了实现该接口的类获取Bean的能力。

本章不谈具体的实现逻辑,因为IOC的实现是一个复杂的过程,在不了解Spring设计意图的前提下盲目去讨论其直接实现类AbstractBeanFactory的实现逻辑会容易让人迷茫,因为其中参杂着其他许多类与接口的部分。相信跟着源码debug过的同学深有体会。其中Bean的缓存是由DefaultSingletonRegistry实现的,Bean的构建和装配等逻辑又是由AbstractAutowireCapableBeanFactory类实现的,这些部分的逻辑又被嵌入在获取Bean的逻辑中,所以通过debug去追溯源码执行逻辑的方式并不可取。

接口方法说明

下面提供对BeanFactory中函数的简单说明,可看可不看。因为大概的作用在前面已经点的差不多了,有了解的同学可以不用看这部分。

Object getBean(String name) throws BeansException;

根据name或者alias获取容器中的Bean

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

通过传入的name查找到Bean然后转成requiredType的类型,如果找不到会抛出 NoSuchBeanDefinitionException.
如果转化类型失败会抛出BeanNotOfRequiredTypeException.

Object getBean(String name, Object... args) throws BeansException;

返回一个实例,该实例可以是指定bean的共享或独立的。
允许指定显式构造函数自变量/工厂方法自变量,并覆盖Bean定义中指定的默认自变量(如果有) 。
注意,如果Bean已经被创建了,那么通过这个方式就无法将参数放进去了。

<T> T getBean(Class<T> requiredType) throws BeansException;

根据类型查找Bean,如果找不到Bean会抛出 NoSuchBeanDefinitionException;
如果找到不止一个,则抛出NoUniqueBeanDefinitionException

<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

根据type查找Bean,如果该Bean未被实例化,那么可以将传入的参数对Bean进行DI

<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

getBeanProvider()方法用于获取指定bean的ObjectProvider。
ObjectProvider是用与延迟构造Bean的,因为正常直接通过getBean来获取Bean会使得容器直接实例化Bean,但有些时候我们可能并不希望这样。ObjectProvider正好可以用来解决这个问题,它使得我们只有调用了ObjectProvider中的getObject方法才会出发Bean的实例化。这个类不需要深究,不影响IOC的源码理解。

boolean containsBean(String name);

容器中是否包含Bean,按照name或者alias进行查找

boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

判断当前的Bean是单例还是原型的作用域

boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

检查具有给定信息的Bean是否与指定的类型匹配。更具体地说,检查对给定名称的getBean调用是否将返回可分配给指定目标类型的对象。将别名转换回相应的规范bean名称。将询问父工厂是否在该工厂实例中找不到该bean。

Class<?> getType(String name) throws NoSuchBeanDefinitionException;

获取bean对应的class

String[] getAliases(String name);

返回Bean的别名数组

总结

Spring的IOC实际上是由两个部分组成的,以Regisrty结尾的接口赋予了类缓存Bean以及其他需要用到的对象的缓存能力,也就是容器的能力。而本文谈到的BeanFactory及其以BeanFactory结尾的子接口则赋予了实现类访问容器的能力,使得我们可以通过这些接口完成Bean的构建和获取等操作。因此对于IOC的认识需要分为BeanFactory和Registry两个脉络去了解,两条脉络最终在DefaultListableBeanFactory这个类上完成交汇,从而提供真正的IOC功能。

本系列将沿着两条脉络逐步解析,来完成对SpringIOC源码的分析,从而了解Spring的设计思想。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32MP157驱动开发——按键驱动(POLL 机制)

文章目录 “POLL ”机制&#xff1a;APP执行过程驱动使用的函数应用使用的函数pollfd结构体poll函数事件类型实现原理 poll方式的按键驱动程序(stm32mp157)gpio_key_drv.cbutton_test.cMakefile修改设备树文件编译测试 “POLL ”机制&#xff1a; 使用休眠-唤醒的方式等待某个…

BOB_1.0.1靶机详解

BOB_1.0.1靶机详解 靶机下载地址&#xff1a;https://download.vulnhub.com/bob/Bob_v1.0.1.ova 这个靶机是一个相对简单的靶机&#xff0c;很快就打完了。 找到ip地址后对IP进行一个单独的扫描&#xff0c;发现ssh端口被改到25468了&#xff0c;等会儿登陆时候需要用到。 目…

SQL注入原理分析

前言 order by的作用及含义 order by 用于判断显示位&#xff0c;order by 原有的作用是对字段进行一个排序&#xff0c;在sql注入中用order by 来判断排序&#xff0c;order by 1就是对一个字段进行排序&#xff0c;如果一共四个字段&#xff0c;你order by 5 数据库不知道怎么…

物联网场景中的边缘计算解决方案有哪些?

在物联网场景中&#xff0c;边缘计算是一种重要的解决方案&#xff0c;用于在物联网设备和云端之间进行实时数据处理、分析和决策。HiWoo Box作为工业边缘网关设备&#xff0c;具备边缘计算能力&#xff0c;包括单点公式计算、Python脚本编程以及规则引擎&#xff0c;它为物联网…

使用Kmeans算法完成聚类任务

聚类任务 聚类任务是一种无监督学习任务&#xff0c;其目的是将一组数据点划分成若干个类别或簇&#xff0c;使得同一个簇内的数据点之间的相似度尽可能高&#xff0c;而不同簇之间的相似度尽可能低。聚类算法可以帮助我们发现数据中的内在结构和模式&#xff0c;发现异常点和离…

原生求生记:揭秘UniApp的原生能力限制

文章目录 1. 样式适配问题2. 性能问题3. 原生能力限制4. 插件兼容性问题5. 第三方组件库兼容性问题6. 全局变量污染7. 调试和定位问题8. 版本兼容性问题9. 前端生态限制10. 文档和支持附录&#xff1a;「简历必备」前后端实战项目&#xff08;推荐&#xff1a;⭐️⭐️⭐️⭐️…

服务网格技术对比:深入比较Istio、Linkerd和Envoy等服务网格解决方案的优缺点

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

解决mysqld服务启动失败

1、进程 首先查看下mysql进程: ps -aux | grep mysql有进程号 2、所有者和所属组为mysql 查看/usr/local/MySQL/data/mysqld.pid所有者和所属组是否为mysql 原来是权限有问题&#xff0c;那么更改权限&#xff08;还需要加权限&#xff09;3、 重新启动服务

Kubernetes.Service—使用源 IP

使用源 IP 运行在 Kubernetes 集群中的应用程序通过 Service 抽象发现彼此并相互通信&#xff0c;它们也用 Service 与外部世界通信。 本文解释了发送到不同类型 Service 的数据包的源 IP 会发生什么情况&#xff0c;以及如何根据需要切换此行为。 准备开始 术语表 本文使用…

阿里云盘自动每日签到无需部署无需服务器(仅限学习交流使用)

一、前言 阿里云盘自动每日签到&#xff0c;无需部署&#xff0c;无需服务器 执行思路&#xff1a;使用金山文档的每日定时任务&#xff0c;执行阿里云盘签到接口。 二、效果展示&#xff1a; 三、步骤&#xff1a; 1、进入金山文档网页版 金山文档官网&#xff1a;https:…

EXCEL数据自动web网页查询----高效工作,做个监工

目的 自动将excel将数据填充到web网页&#xff0c;将反馈的数据粘贴到excel表 准备 24KB的鼠标连点器软件&#xff08;文末附链接&#xff09;、Excel 宏模块 优势 不需要编程、web验证、爬虫等风险提示。轻量、稳定、安全。 缺点 效率没那么快 演示 宏环境 ht…

QT第四讲

思维导图 基于QT的网络聊天室 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器类 #include<QTcpSocket> //客户端类 #include<QMessageBox> //对话框类 #include<QList…

【Terraform学习】Terraform-AWS部署快速入门(快速入门)

Terraform-AWS部署快速入门 实验步骤 连接到 Terraform 环境 SSH 连接到Terraform 环境(名为MyEC2Instance的实例) 在 Amazon Web Services &#xff08;AWS&#xff09; 上预置 EC2 实例 用于描述 Terraform 中基础结构的文件集称为 Terraform 配置。您将编写一个配置来定义…

R-并行计算

本文介绍在计算机多核上通过parallel包进行并行计算。 并行计算运算步骤&#xff1a; 加载并行计算包&#xff0c;如library(parallel)。创建几个“workers”,通常一个workers一个核&#xff08;core&#xff09;&#xff1b;这些workers什么都不知道&#xff0c;它们的全局环…

【雕爷学编程】MicroPython动手做(10)——零基础学MaixPy之神经网络KPU2

KPU的基础架构 让我们回顾下经典神经网络的基础运算操作&#xff1a; 卷积&#xff08;Convolution&#xff09;:1x1卷积&#xff0c;3x3卷积&#xff0c;5x5及更高的卷积 批归一化&#xff08;Batch Normalization&#xff09; 激活&#xff08;Activate&#xff09; 池化&…

Meta-Transformer 多模态学习的统一框架

Meta-Transformer是一个用于多模态学习的新框架&#xff0c;用来处理和关联来自多种模态的信息&#xff0c;如自然语言、图像、点云、音频、视频、时间序列和表格数据&#xff0c;虽然各种数据之间存在固有的差距&#xff0c;但是Meta-Transformer利用冻结编码器从共享标记空间…

14:00面试,14:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到5月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%,…

音视频——封装格式原理

视频解码基础 一、封裝格式 ​ 我们播放的视频文件一般都是用一种封装格式封装起来的&#xff0c;封装格式的作用是什么呢&#xff1f;一般视频文件里不光有视频&#xff0c;还有音频&#xff0c;封装格式的作用就是把视频和音频打包起来。 所以我们先要解封装格式&#xff0…

【C语言day07】

在调用函数的时候&#xff0c;真实传递给函数的是实参&#xff0c;函数定义部分函数名后的参数是形参。 形参和实参的名字是可以相同的&#xff0c;在函数调用的时候&#xff0c;形参是实参的一份临时拷贝&#xff0c;分别占用不同的内存空间&#xff0c;所以A正确&#xff0c;…

使用CRM分析数据有哪些功能?

CRM数据分析软件可以帮助企业增强竞争力&#xff0c;并更好地了解客户需求及市场变化&#xff0c;助力企业数据分析&#xff0c;并提供实时更新的数据和分析结果&#xff0c;CRM数据分析软件的主要特点是什么&#xff1f;包括以下6个特点。 CRM数据分析软件的主要功能通常包括…