Spring BeanFactory 源码中是如何创建对象
目录
整体流程
上篇博客【 源码解析-Spring 如何从配置文件中读取文件】 中,我们聊到Spring中如何从配置中读取文件并转成BeanDefinitions 。今天我们继续来聊一下,Spring 如何基于 BeanDefinitions
加工成最终的对象。
主要的步骤和把大象装入冰箱一样,都分了三步。用我们一个简单造车的场景来比喻,这三步对应的是:
图1
- 实例化 (搭建车子的外壳)
- 属性填充 (车子里边座椅等填充)
- 初始化 (让车子初始跑起来)
过程解析
实例化-instantiateBean
这一步大体可以理解为一个复杂的 new Student(),也就是把这个对象创建出来。通过我们记录的 对象的类型,名称等属性,对对象进行实例化。但是注意这里的 student 里属性还是空的。
这里要考虑的主要问题就是,创建的对象是单例还是多例,单例怎么办,多例怎么办等。
属性填充
属性填充的一种主要方式就是set 。setName(String name);
这里要考虑的主要问题就是 Spring 通过配置文件的那种方式进行属性的注入。比如用户注入,或是容器注入等。
初始化
初始化这里,就是比如对对象设置了一些初始化方法啥的。都会在这一步里来进行。
对象加工 BeanPostProcessor
除了上面三个步骤外,Spring 还会加入一个对象加工(BeanPostProcessor)。而这个对象加工,在初始化之前和初始化之后都有。这样可以解除掉加工代码的耦合性。
也就是我们把上边 图1 再展开一些就是这样。如图2 所示。
图2
代码部分
有了上边的流程,接下来我们再代入主要的代码部分,细化下其中的步骤。如图所示。
这张图展示了Spring创建Bean的流程。
首先,通过读取Bean的配置信息,Spring可以知道要创建哪些对象以及如何创建这些对象。
然后,Spring会实例化这些对象,并对它们进行依赖注入,即设置它们的属性值。
接下来,Spring会对这些对象进行初始化,例如调用它们的初始化方法。
最后,Spring会返回创建的Bean实例,供应用程序使用。
在这个流程中,有一个特殊的对象加工步骤,即BeanPostProcessor。BeanPostProcessor在Bean实例化和初始化之前或之后对Bean实例进行加工,以解除加工代码的耦合性。
代码入口:
@Test
public void test() {
//1 获得Spring的工厂
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
//2 通过工厂类 获得 对象
Person person = (Person) ctx.getBean("person");
System.out.println("person = " + person);
}
核心路径:
ctx.getBean
org.springframework.beans.factory.BeanFactory#getBean(java.lang.String)
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
这里边,我们重点提一个问题,当A对象引用B对象,B对象里也引用A对象的时候。在属性填充A对象的属性时,B对象要创建的话,B对象里还需要A对象,而A对象还没创建完?这种典型的循环引用,Spring是怎么解决的?我们下篇文章里聊
总结
Spring创建Bean的流程可以简单概括为以下几个步骤:
- 加载Bean的配置信息
- 实例化Bean
- 依赖注入
- 初始化Bean
- 返回Bean实例
本文介绍了 Spring BeanFactory 源码中创建对象的过程,分为实例化、属性填充和初始化三个步骤。在此基础上,介绍了对象加工的 BeanPostProcessor 这一步骤,以解除加工代码的耦合性。最后,总结了 Spring 创建 Bean 的流程,包括加载 Bean 的配置信息、实例化 Bean、依赖注入、初始化 Bean 和返回 Bean 实例。
【结尾 来自 notion AI】