1、循环依赖
就是A对象依赖了B对象,B对象依赖了A对象。
// A依赖了B
class A{
public B b;
}
// B依赖了A
class B{
public A a;
}
在 Spring 中,只有同时满足以下两点才能解决循环依赖的问题:
1)依赖的 Bean 必须都是单例。( Spring 只支持单例的循环依赖)
2)依赖注入的方式,必须不全是构造器注入,且 beanName 字母序在前的不能是构造器注入。
2、解决方案
三级缓存
一级缓存为:singletonObjects;
二级缓存为:earlySingletonObjects;
三级缓存为:singletonFactories;
/** 存储所有已创建完毕的单例 Bean (完整的 Bean) */
private final Map singletonObjects = new ConcurrentHashMap(256);
/** 存储所有仅完成实例化,但还未进行属性注入和初始化的 Bean */
private final Map singletonFactories = new HashMap>(16);
/** 存储能建立这个Bean的工厂,通过工厂能获取这个Bean,延迟化 Bean 的生成,工厂生成的Bean会塞入二级缓存 */
private final Map earlySingletonObjects = new HashMap(16);
步骤:
①首先,获取这个bean的时候,会根据beanName去一级缓存中寻找是否存在;如果存在则直接返回,否则继续执行;
②看对应的bean是否正在创建中,如果没有在创建,则返回null;如果正在创建,则去二级缓存中查找对应的bean,找到则返回,找不到则继续执行;
③去三级缓存中查询对应beanName的工厂,如果没有,则返回null;如果有这样的工厂,则通过工厂穿件这个bean返回,并且放入二级缓存;
为什么一定要使用三级缓存?
使用三级缓存是为了解决AOP代理对象的问题。
如果有代理的话,那么我们想要直接拿到的是代理对象。
也就是说如果 A 需要被代理,那么 B 依赖的 A 是已经被代理的 A,所以我们不能返回 A 给 B,而是返回代理的 A 给 B。
这个工厂的作用就是判断这个对象是否需要代理,如果否则直接返回,如果是则返回代理对象。
正常代理对象的生成是基于后置处理器,是在被代理的对象初始化后期调用生成的,所以如果你提早代理了其实是违背了 Bean 定义的生命周期。
所以 Spring 先在一个三级缓存放置一个工厂,如果产生循环依赖,那么就调用这个工厂提早得到代理对象。
如果没产生依赖,这个工厂根本不会被调用,所以 Bean 的生命周期就是对的。