Spring Bean 实例化和 IOC 依赖注入:深入源码分析(二)
2023-10-03 07:40:54
引言
Spring 框架是当今 Java 开发中广泛采用的依赖注入框架。它通过其 bean 工厂管理 bean 的生命周期,包括实例化和依赖注入。在本文中,我们将深入研究 Spring 框架,具体分析 bean 实例化和 IOC 依赖注入的过程。我们将使用 Spring 5.3.23 版本,并专注于 DefaultListableBeanFactory 的 preInstantiateSingletons() 方法,这是 bean 实例化和依赖注入的关键入口点。
bean 的生命周期
在 Spring 框架中,bean 经历了一个明确的生命周期,包括:
- 实例化: 创建 bean 实例。
- 属性填充: 填充 bean 的属性值。
- 依赖注入: 解析和注入 bean 的依赖项。
- 初始化: 执行 bean 的初始化方法。
- 销毁: 在 bean 不再需要时销毁它。
DefaultListableBeanFactory.preInstantiateSingletons()
DefaultListableBeanFactory.preInstantiateSingletons() 方法是 bean 实例化和依赖注入过程的入口点。它被调用来预实例化所有单例 bean,以便在需要时快速访问它们。
preInstantiateSingletons() 方法的主要步骤如下:
- 获取所有单例 bean 定义: 从 bean 工厂获取所有标记为单例作用域的 bean 定义。
- 排序 bean 定义: 根据依赖关系对 bean 定义进行排序,确保依赖 bean 在父 bean 之前实例化。
- 实例化 bean: 遍历排序后的 bean 定义并创建它们的实例。
- 属性填充: 填充 bean 的属性值。
- 依赖注入: 解析和注入 bean 的依赖项。
- 初始化 bean: 执行 bean 的初始化方法。
依赖关系解析算法
依赖关系解析是 preInstantiateSingletons() 方法的关键部分。Spring 使用了一种深度优先算法来解析依赖关系:
- 获取 bean 的依赖项: 从 bean 定义中获取依赖项列表。
- 递归解析依赖项: 对于每个依赖项,递归调用依赖关系解析算法来解析其依赖项。
- 检查循环依赖: 在解析过程中,Spring 会检查循环依赖,并抛出异常来防止无限递归。
- 实例化和注入: 一旦依赖关系被解析,Spring 将实例化依赖 bean 并将其注入到主 bean 中。
示例代码
为了说明 bean 实例化和依赖注入的过程,让我们考虑以下示例代码:
public class BeanA {
private BeanB beanB;
public BeanA(BeanB beanB) {
this.beanB = beanB;
}
}
public class BeanB {
private BeanC beanC;
public BeanB(BeanC beanC) {
this.beanC = beanC;
}
}
public class BeanC {
}
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
BeanA beanA = context.getBean(BeanA.class);
}
}
在示例中,BeanA 依赖于 BeanB,BeanB 依赖于 BeanC。当 DefaultListableBeanFactory.preInstantiateSingletons() 方法被调用时,它将按照以下顺序实例化和注入 bean:
- BeanC
- BeanB
- BeanA
Spring 会自动解析依赖关系,并根据给定的构造函数参数注入 bean。
结论
在本文中,我们深入分析了 Spring bean 实例化和 IOC 依赖注入过程。我们重点研究了 DefaultListableBeanFactory.preInstantiateSingletons() 方法,了解了它如何管理 bean 生命周期并解析依赖关系。通过理解这些机制,我们可以更深入地了解 Spring 框架并更有效地构建基于 Spring 的应用程序。