Spring中Bean对象之间的循环依赖问题
一、对于使用Autowired注解导致的循环依赖
使用缓存解决循环依赖,Spring中的三个缓存
- 一级缓存: 存储完整的单例Bean
- 二级缓存:存储半成品单例Bean
- 三级缓存:打破循环
预备知识
- Spring中一个bean的创建过程大概为:实例化->初始化(自定义属性的依赖注入,aware属性的依赖注入,进行AOP)->使用->销毁
- 在实例化的时候,根据构造函数创建一个bean对应的实例,在进行初始化的时候会把使用@Autowired注解的对象进行依赖注入(@Autowired注解默认required
= true,即使用该注解的对象实例必须存在)
举例说明
下面的代码里面,AService里面依赖注入了BService,BService里面依赖注入了AService
@Service
public class AService{
@Autowired
private BService bService;
public AService(){}
}
@Service
public class BService{
@Autowired
private AService aService;
public BService(){}
}
在实例化的过程中,两个bean对象都可以成功的进行实例化,在进行初始化的时候,AService实例里面要依赖注入BService实例,就会执行下面的过程:
需要判断当前bean对象是否需要AOP,如果需要AOP的话,需要进行提前AOP,并且把半成品的代理对象放入到二级缓存里面,而不是把半成品的普通对象放入到二级缓存里面
然后对bean实例进行其他属性的赋值,这个时候的bean对象就是完整的对象,把完整的对象放入到单例池里面
Spring靠着三个缓存解决了循环依赖
二、对于构造函数导致的循环依赖
1. 使用@Lazy注解
使用Lazy注解打破循环,Spring会直接生成BService的代理对象(和AOP的代理对象没有关系,是Spring直接基于cglib生成的代理对象,不涉及去创建BService的bean,直接创建BService的代理),然后就把BService的代理对象传给A。
2. 使用工厂方法来创建bean对象
使用工厂方法创建对象,只有在对象使用的时候才会进行创建,这样就不会出现循环依赖