循环依赖只存在于 Spring 中, 是因为 Spring 创建 Bean 的流程中, 依赖注入阶段, 会先从单例池中找, 没有再从定义池中找, 针对定义池中找到的候选项会通过 getBean 创建其单例并缓存到单例池, 此机制导致了存在循环依赖的问题. 如 A 依赖 B, B 依赖 A, getBean A 的时候, A 还没有入单例池. 发现依赖 B, 又去 getBean B, 又发现依赖 A, 在单例池中没有找到 A, 在定义池中找到了 A, 所以又去 getBean A, …, Spring 通过三级缓存的方式, 解决了这个问题
Spring 完成依赖注入的核心方法是 BeanFactory.resolveDependency, 做先类型后名称的筛选, 取到符合条件的候选项, 候选项如果来自单例池, 则是一个 Bean, 如果来自定义池, 则就是一个 Class 对象, 在这里会对其的 BeanName 做 getBean 操作, 生成 Bean 并缓存到单例池. 这个流程可以简化为, Spring 创建 Bean 的流程中的依赖注入阶段, 会对其依赖做 getBean 操作
其中 findAutowireCandidates 步骤会从单例池和定义池中找符合类型条件的 BeanName, 如果当前依赖的 Bean 还没有被生成单例并缓存, 则在单例池中找不到, 就会去定义池中找, 定义池中通过遍历 beanDefinitionNames 的方式拿到每一个 BeanDefinition, 第一步就是判断是否为 FactoryBean, 内部就会判断 beanClass 字段中的全限定类名是否被加载成为 Class 对象, 没有就会执行类加载, 并缓存结果
假设有AB两个类, A依赖B且B依赖A, 遍历创建单例Bean时先A再B, A依赖B所以去创建B, B依赖A所以去创建A, 陷入循环
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
需要提前暴露A, 让B找的到A, 即增加一个缓存, 打破循环依赖