Spring IoC 的底层原理
核心
xml解析、工厂模式、反射
实现原理
首先,通过XML解析来加载spring.xml配置文件,该配置文件包含了Bean的定义和配置信息。
然后,使用反射机制调用无参构造函数动态创建对象。Spring IoC容器会根据配置文件中的Bean定义,通过反射机制实例化Bean对象。
接下来,通过调用对象的setter方法完成对象属性的赋值。Spring IoC容器会根据配置文件中的属性配置,将相应的值注入到对象中。
最后,将创建好的对象放入IOC容器中。Spring IoC容器会将创建好的Bean对象存储在一个类似于HashMap的容器中,以便后续根据需要获取对象。
当需要使用某个对象时,可以通过调用getBean方法从IOC容器中获取对象。getBean方法会根据指定的Bean的ID或类型,从IOC容器中查找并返回对应的对象。
需要注意的是,Spring提供了两种IoC容器的实现方式:BeanFactory和ApplicationContext。BeanFactory是Spring的基础接口,提供了IoC容器的基本功能;而ApplicationContext是BeanFactory的子接口,提供了更多的功能和扩展,是Spring中最常用的IoC容器之一。
骚戴理解:
- 第一种接口(BeanFactory接口):此接口是IOC容器的基本实现,也是Spring框架内部使用的接口,不提供给开发人员进行使用,此接口是在加载配置文件时不会创建对象,而是在获取对象或使用时才去创建对象
- 第二个接口(ApplicationContext):此接口是BeanFactory接口的子接口,提供了更强大的功能,开发人员一般用的都是这个接口,此接口在加载配置文件时就会创建配置文件中所配置的对象
深入挖掘
Spring组件按其所承担的角色可以划分为两类:
1)物料组件:Resource、BeanDefinition、PropertyEditor以及最终的Bean等,它们是加工流程中被加工、被消费的组件,就像流水线上被加工的物料;
- BeanDefinition:Spring通过BeanDefinition将配置文件中的<bean>配置信息转换为容器的内部表示,并将这些BeanDefinition注册到BeanDefinitionRegistry中。Spring容器的后续操作直接从BeanDefinitionRegistry中读取配置信息。
2)加工设备组件:ResourceLoader、BeanDefinitionReader、BeanFactoryPostProcessor、InstantiationStrategy以及BeanWrapper等组件像是流水线上不同环节的加工设备,对物料组件进行加工处理。
- InstantiationStrategy:负责实例化Bean操作,相当于Java语言中new的功能,并不会参与Bean属性的配置工作。属性填充工作留待BeanWrapper完成
- BeanWrapper:继承了PropertyAccessor和PropertyEditorRegistry接口,BeanWrapperImpl内部封装了两类组件:(1)被封装的目标Bean(2)一套用于设置Bean属性的属性编辑器;具有三重身份:(1)Bean包裹器(2)属性访问器 (3)属性编辑器注册表。PropertyAccessor:定义了各种访问Bean属性的方法。PropertyEditorRegistry:属性编辑器的注册表
该图描述了Spring容器从加载配置文件到创建出一个完整Bean的作业流程:
1、ResourceLoader从存储介质中加载Spring配置信息,并使用Resource表示这个配置文件的资源;
2、BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个<bean>解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
解析:这里的前两步对应这上面核心的XML解析,后面就都是反射,而工厂模式体现在整个IOC容器就是一个工厂,一个生产对象的工厂,要什么对象就告诉这个工厂那个对象的名称,工厂就把对应的对象给你,你并不需要知道这个对象怎么来的,就像你开口找爸妈要钱一样,只管要没要到钱,不用管这个钱爸妈是怎么赚的
3、容器扫描BeanDefinitionRegistry中的BeanDefinition,使用Java的反射机制自动识别出Bean工厂后处理后器(实现BeanFactoryPostProcessor接口)的Bean,然后调用这些Bean工厂后处理器对BeanDefinitionRegistry中的BeanDefinition进行加工处理。主要完成以下两项工作:
- 1)对使用到占位符的<bean>元素标签进行解析,得到最终的配置值,这意味对一些半成品式的BeanDefinition对象进行加工处理并得到成品的BeanDefinition对象;
- 2)对BeanDefinitionRegistry中的BeanDefinition进行扫描,通过Java反射机制找出所有属性编辑器的Bean(实现java.beans.PropertyEditor接口的Bean),并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry);
4.Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并调用InstantiationStrategy着手进行Bean实例化的工作;
5.在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,BeanWrapper提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefinition以及容器中属性编辑器,完成Bean属性的设置工作;
6.利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean。
源码好文参考:最详细的Spring核心IOC的源码分析