Spring框架源码脉络分析(一):IoC与容器、Bean和BeanDefinition
系列文章概述
- 系列文章主页:Spring框架源码脉络分析总结
- 阅读建议:读者至少要使用过Spring框架,了解Spring的配置方法,包括Xml文件配置和注解配置。
- 分析的源码版本:
spring-framework : 5.2.0.RELEASE
- 官方参考文档:Spring Framework Documentation
- 本文主要以分析Spring源码模块脉络为主,主要带领读者理清Spring运行的流程和脉络,不会深究一些知识细节,避免陷入细节无法自拔,所以仅贴出来核心的源码进行分析备注,对于每个步骤的细节,需要读者自行深入了解
IoC与容器
IoC:即控制反转机制。在Spring中的实现表现为IoC容器,属于Spring Core模块最核心的部分。
IoC其实是一种设计思想,其本质就是将对象的创建、依赖关系的管理以及生命周期的的控制交由IoC容器,或者说是框架来管理,解放了码农的双手。
IoC的存在离不开另外一个设计思想——依赖注入(DI)。
- 依赖注入最直观的解释就是一个实例化对象只接受一个参数——已经实例化的对象。也就是说一个对象A中如果依赖另一个对象B,必须直接注入一个已经实例化的对象B,对象A本身不关注对象B如何实例化的,这样就将对象间的依赖尽可能的解耦。
- 而控制对象实例化和操作对象注入的【控制】权限就交给了第三方——spring框架,进行控制反转,这就是IoC。
- 既然有了这种设计思想,那么对象B是如何注入对象A中去的呢?其实很简单,就是通过四种常用的注入方式:Set注入、接口注入、注解注入和构造器注入。
- 所以IoC、依赖反转和IoC容器的关系可以看做下图:
IoC在spring中依托于一个类似工厂的IoC容器,将所有的bean都托管在容器中,随时供框架进行调用,spring的容器可以让码农避免在各处使用new来创建类,并且做到了统一维护,码农在创建实例的时候不需要了解其中的细节。
什么是容器:Spring官方文档中对容器的描述如下:
The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans.
意思是org.springframework.context.ApplicationContext
这个接口就代表了Spring的容器,这个容器负责实例化、配置以及装配一个Bean。
所以简单的从代码上看,我们可以认为容器就是一个ApplicationContext
的实现类的实例化对象。当我们使用Spring框架对对象进行管理时,Spring框架会自动为我们创建一个容器用来管理对象,这个容器是Spring框架的核心。我们将在第二章节中重点来分析Spring中的容器类。
Bean和BeanDefinition
在Spring中,Bean是一等公民,我们常说的对象在Spring中就描述为Bean。Bean的本质其实就是Java对象,是我们期望从Spring容器中获取到的实例。
而如果我们去阅读Spring的源码,会发现在Spring中大量操作的是一种名为BeanDefinition的类,而不是Bean。在Spring中,BeanDefinition是对Bean的定义与描述,Bean和BeanDefinition的关系有点像装饰器模式的增强:
- Spring容器在运行过程中需要对Bean,也就是我们的Java对象进行操作与管理,其中需要进行一些额外的操作,而这些操作在Bean中是没有办法体现的。所以Spring提供了一种无侵入式的方法,对Bean进行包装,将各种描述信息和控制方式信息包装进BeanDefinition中,也就是说BeanDefinition中既有Bean对象的信息,又有描述和控制信息。
- 那么这些额外的信息是什么呢:其实就是我们经常在xml或者注解文件中使用的配置属性,比如scope属性用来控制Bean是单例还是多例,lazy-init属性用来控制Bean实例是否延迟加载,primary设置为true的Bean将会是类的优先实现类等等。这些额外的信息和参数,就将随着Bean对象一起被封装进BeanDefinition中,以便于Spring根据用户传入的需求对Bean进行管理。
Spring中BeanDefinition的接口体系如下图:
其中各接口与类的作用如下:
-
BeanMetadataElement
接口: BeanDefinition元数据,定义了返回该Bean的来源的抽象接口。 -
AttributeAccessor
接口: 定义了对元数据访问的抽象接口。 -
AttributeAccessorSupport
抽象类:AttributeAccessorSupport
是实现了AttributeAccessor
的抽象类,实现了一些基础通用方法,内部由LinkedHashMap
实现。 -
BeanDefinition
接口: BeanDefinition体系的顶级基础接口,定义了存储描述Bean的元数据的各种变量与方法,包括Bean的类名、scope属性、是否懒加载等一系列属性。 -
AbstractBeanDefinition
抽象类: BeanDefinition接口的抽象实现类,统一实现了BeanDefinition接口定义的一部分操作,定义了BeanDefinition很多默认的属性。同时还继承了BeanMetadataAttributeAccessor
类,BeanMetadataAttributeAccessor
类又继承自AttributeAccessorSupport
,所以AbstractBeanDefinition
还同时具备对元数据访问的各种方法实现。正是在AbstractBeanDefinition
基础上,Spring又衍生出了一系列的BeanDefinition。Spring框架的设计中,充满了这种通过上下继承关系来对基类进行功能扩充与功能分隔的类体系。
从AbstractBeanDefinition
上衍生出来的几个类:
-
RootBeanDefinition
类: 这是一个可以合并的BeanDefinition,在Spring容器运行期间,容器会对BeanDefinition进行合并,以保证BeanDefinition是最新的,返回的就是RootBeanDefinition。 -
GenericBeanDefinition
类: Spring2.5之后出现的通用BeanDefinition实现类,用来操作和返回BeanDefinition,可以灵活设置自己的parentBeanDefinition
,而不像RootBeanDefinition
一样硬编码,一般我们通过注解配置的bean以及我们的配置类(除@Bean外)的BeanDefiniton类型都是GenericBeanDefinition
。 -
ChildBeanDefinition
类: 现在已经被GenericBeanDefinition
所替代了。GenericBeanDefinition
相对于ChildBeanDefinition
更灵活,GenericBeanDefinition
不需要强制指定parentName
。
关于Bean
和BeanDefinition
的区别,就说到这,最后再次重申本文章的内容:本文主要以分析Spring源码模块脉络为主,主要带领读者理清Spring运行的流程和脉络,不会深究一些知识细节,避免陷入细节无法自拔,所以虽然BeanDefinition很重要,是Spring的基石,但还是以介绍为主,并不会深入进入分析源码,意在最快时间带领读者进入Spring的脉络与流程,如果对某个接口或者某个实现类的逻辑比较感兴趣,可以自行阅读对应的源码。
- 学习分享 | Flipped Ciphertext Bits
- 聊一下JavaScript定时器
- java redis 通用组建
- 学习分享 | Padding Oracle
- FastJson 反序列化注意事项
- Python编写渗透工具学习笔记二 | 0x05编写脚本劫持tcp会话
- linux下socket编程
- java与openssl的rsa算法互
- Python编写渗透工具学习笔记二 | 0x04编写程序分析流量检测ddos攻击
- Python编写渗透工具学习笔记二 | 0x03用python构建ssh僵尸网络
- Python编写渗透工具学习笔记二 | 0x02利用FTP与web批量抓肉鸡
- linux 网络编程之信号机制
- im4java + imagemagic 搭建一个图片处理服务
- # Java 一步一步实现高逼格的字符串替换工具(二)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Flutter基础widgets教程-IconButton篇
- Flutter基础widgets教程-Image篇
- Go - 学习 grpc.Dial(target string, opts …DialOption) 的写法
- Flutter基础widgets教程-IntrinsicHeight篇
- Flutter基础widgets教程-Baseline篇
- springcloud本地开发的微服务如何调用远程k8s的微服务
- Flutter基础widgets教程-LimitedBox篇
- 算法:滑动窗口(二)
- Flutter基础widgets教程-LinearProgressIndicator篇
- Flutter基础widgets教程-ListTile篇
- 深入剖析 linux GCC 4.4 的 STL String
- Flutter基础widgets教程-MaterialApp篇
- 如何使用Visual Studio Code开发Django项目
- Flutter基础widgets教程-Padding篇
- Flutter基础widgets教程-Placeholder篇