就是我们有两个服务,A服务,B服务,然后我们在A里注入了B,然后在B里注入了A,这就是循环依赖了,这种情况如果我们不解决的话,那就会出现一个相互依赖注入的死循环。
/** 一级缓存 单例缓存池 用于保存我们所有的单实例bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存 保存半成品bean实例,当对象需要被AOP切面代时,保存代理bean的实例beanProxy*/
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 三级缓存 存放ObjectFactory,传入的是匿名内部类,ObjectFactory.getObject() 方法最终会
调用getEarlyBeanReference()进行处理,返回创建bean实例化的lambda表达式。*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
前置知识:Spring的单例对象的初始化主要分为三步: (1)createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象 (2)populateBean:填充属性,这一步主要是多bean的依赖属性进行填充 (3)initializeBean:调用spring xml中的init 方法。
循环依赖涉及的重点方法是DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
//一个纯bean获取流程,这里不进行创建
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从一级缓存singletonObjects获取bean
Object singletonObject = this.singletonObjects.get(beanName);
// 一级缓存没有,判断该bean是否在创建中,通过Set的contains来判断
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从二级缓存中获取bean
singletonObject = this.earlySingletonObjects.get(beanName);
// 二级缓存没有&&允许提前引用
if (singletonObject == null && allowEarlyReference) {
// 从三级缓存中获取lambda表达式
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 如果获取到该lambda表达式,进行回调填充
if (singletonFactory != null) {
// 调用三级缓存的lambda表示获取早期不完整对象
singletonObject = singletonFactory.getObject();
// 写入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 三级缓存移除该bean的lambda表达式
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
现在来分析一下A B循环依赖的情况
流程提前透知一下,便于描述
在创建bean时,会调用doGetBean方法,首先通过getSingleton方法从缓存中看是否能获取到该bean
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
... ... ...
//先从一级缓存singletonObjects中获取,发现获取不到,然后看是否在创建中,显然初次创建时不成立,即getSingleton返回null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
... ... ...
}else {
... ... ...
try {
... ... ...
if (mbd.isSingleton()) {
//getSingleton方法触发createBean回调,进行bean的生命周期
//这里会将当前beanName放入singletonsCurrentlyInCreation,表示当前bean正在创建
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
... ... ...
}
return (T) bean;
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
... ... ...
// 会将当前beanName放入singletonsCurrentlyInCreation,表示当前bean正在创建
beforeSingletonCreation(beanName);
... ... ...
try {
// lambda表达式回到createBean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
... ... ...
}
return singletonObject;
}
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
... ... ...
if (instanceWrapper == null) {
// a. 一般通过createBeanInstancec实例化不完整的BeanServiceA对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
... ... ...
// 默认单例&&默认循环引用&&该bean正在创建,条件成立
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
... ... ...
// b. 将不完整对象以及BeanDefinition代表的lambda表达式写入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// c. 属性填充BeanServiceB
populateBean(beanName, mbd, instanceWrapper);
// d.初始化时调用AOP后置处理器进行AOP处理
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
... ... ...
// e.处理提前暴露的场景,保证返回同一个代理对象
if (earlySingletonExposure) {
// 见上文第1节的节速,由于第二个参数是false,所以只会查到第二季缓存
// 所以这里就是查看第二级缓存能不能取到值,取到就意味着涉及提前AOP
Object earlySingletonReference = getSingleton(beanName, false);
// 涉及提前AOP,从二级缓存中获取提前AOP的代理对象
if (earlySingletonReference != null) {
if (exposedObject == bean) {
// 保证循环依赖且涉及AOP时,返回同一个代理对象,下文有结束
exposedObject = earlySingletonReference;
}
... ... ...
}
}
return exposedObject;
}
上面 addSingletonFactory将不完整对象以及BeanDefinition代表的lambda表达式写入三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 将不完整对象以及BeanDefinition代表的lambda表达式写入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
> 关于属性填充方法的详细介绍可参考链接:属性填充populateBean
当填充BeanServiceB会重复上文第1节中的内容:
同样,会重复上文第1节的内容,但此时会有不一样的处理:
这里涉及Aop,关于Aop源码有兴趣可以查看链接:Aop代理过程
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//遍历后置处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// 调用后置处理器的getEarlyBeanReference进行提前暴露bean
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
lambda回调会调用后置处理器的getEarlyBeanReference,来获取不完整的bean
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 写入earlyProxyReferences,在后面postProcessAfterInitialization会用到
this.earlyProxyReferences.put(cacheKey, bean);
// 判断是否创建代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
属性填充beanServiceA后,此时填充的beanServiceA是不完整的对象, 在initializeBean初始化调用后置处理器的postProcessAfterInitialization方法
由于BeanServiceB不涉及AOP,所以返回原始的B对象,此时填充的beanServiceA还是不完整的对象
BeanServiceB不涉及AOP,getSingleton返回null,所以直接返回原始对象exposedObject
beanServiceB生命周期执行完,返回到3.1节第14行的getSingleton方法,此时返回的还是不完整的beanServiceB对象 singletonsCurrentlyInCreation移除bean,表明不再是正在创建的bean
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
... ... ...
// 会将当前beanName放入singletonsCurrentlyInCreation,表示当前bean正在创建
beforeSingletonCreation(beanName);
... ... ...
try {
// lambda表达式回到createBean
singletonObject = singletonFactory.getObject();
newSingleton = true;
... ... ..
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// singletonsCurrentlyInCreation中移除beanName,表示该bean不是正在创建了
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 将不完整的beanServiceB对象写入一级缓存,移除二、三级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
beanServiceB“不完整对象”写入一级缓存,移除二、三级缓存
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 写入一级缓存
this.singletonObjects.put(beanName, singletonObject);
// 移除二、三级缓存
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
此时ioc容器已经有了beanServiceB,虽然暂时还是不完整的,因为A还没填充初始化完 当beanServiceA填充完beanServiceB后,使得互相循环依赖对方,此时二者都变成了完整的bean 此时一级缓存的beanServiceB也由不完整的bean变成了完整的bean,因为是同一个地址 A涉及AOP,所以循环依赖时,A会进行提前AOP,所以B中填充的是A的代理对象 当A填充完B时,构成互相循环依赖对方
由于beanServiceA提前AOP了,所以所以earlyProxyReferences有beanServiceA(见上文3.1.2.1.1) remove返回原始的bean,即earlyProxyReferences对应的value,条件不成立,直接==返回原始bean ==
beanServiceA涉及提前AOP,getSingleton返回保存在二级缓存中提前AOP的代理对象A
这里面有exposedObject == bean判断,这就是为什么上述3.1.4中AOP后置处理器返回原始bean的原因 条件成立,将代理对象赋值放回,保证返回同一个代理对象,即B中的A和A都是同一个代理对象
同3.1.2.4节一样,beanServiceA生命周期执行完,会将beanServiceA写入一级缓存,移除二、三级缓存
该场景大概流程如下图,详细可见上文介绍
现有逻辑是,三级缓存的操作是在synchronized代码块里面操作的,是安全的
那为什么要用synchronized而不直接用ConcurrentHashMap来保证线程安全呢? 二级缓存put的同时要保证三级缓存remove;三级缓存put时要保证二级缓存remove,也就是说二三级缓存操作要保证原子性 因为要保证同一个bean是单例的,不然都会lambda回调创建bean,就不是单例的了 如果使用ConcurrentHashMap并不能保证二三级缓存操作的原子性,所以要用synchronized 这三级缓存都是在synchronized内操作的,至于一级缓存为什么用ConcurrentHashMap,可能其他场景的原因吧,我也不不清楚
主要用于循环依赖的bean需要AOP时提前AOP 如果没有第三级缓存,那么getSingleton就返回null,就会再次传教A,导致一直循环创建,现有逻辑就不对.
那如果将实例化的原始对象放入二级缓存呢? 没有第三级缓存,就无法提前AOP,则B属性填充完的A为A原始对象 而A在属性填充完B后,需要进行AOP,则经过AOP后置处理器会去创建代理对象A返回 这就导致B的属性A不是代理对象,而A却是代理对象,这与Spring的单例bean是矛盾的。
参考