Spring 在哪些情况下会出现循环依赖错误?哪些情况下能自身解决循环依赖,又是如何解决的?本文将介绍笔者通过本地调试 Spring 源码来观察循环依赖的过程。
1. 注解属性注入
首先本地准备好一份 Spring 源码,笔者是从 Github 上 Clone 下来的一份,然后用 IDEA 导入,再创建一个 module 用于存放调试的代码。
本次调试有三个类,A、B 通过注解 @Autowired 标注在属性上构成循环依赖,Main 为主函数类。
@Component("A")
public class A {
@Autowired
B b;
}
@Component("B")
public class B {
@Autowired
A a;
}
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
A a = (A) context.getBean("A");
B b = (B) context.getBean("B");
}
}
可以先试着运行下,并不会报错,说明这种情况下的循环依赖能由 Spring 解决。
我们要观察如何解决循环依赖,首先需要知道 @Autowired
标注的属性是如何注入的,如 B 是怎么注入到 A 中的。
由于 A、B 的 scope 是 single,且默认 non-lazy,所以在 ClassPathXmlApplicationContext
初始化时会预先加载 A、B,并完成实例化、属性赋值、初始化等步骤。ClassPathXmlApplicationContext
的构造方法如下:
其中 refresh
是容器的启动方法,点进去,然后找到我们需要的那一步,即实例化 A、B 的步骤:
finishBeanFactoryInitialization
会先完成工厂的实例化,然后在最后一步实例化 A、B:
preInstantiateSingletons
将依次对 non-lazy singleton 依次实例化,其中就有 A、B:
A、B 不是工厂类,则直接通过 getBean
触发初始化。首先会触发 A 的初始化。
getBean
=&