
好的博客:面试必杀技,讲一讲Spring中的循环依赖
什么是循环依赖?
循环依赖是指,A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依赖 A。它们之间的依赖关系如下
什么情况下循环依赖可以被处理?
如何解决循环依赖?
三级缓存在循环依赖中的使用:
这里我们假设一个场景进行讲解:ServiceA、ServiceB相互依赖。
先来分析一个最简单的例子
@Component
public class A {
// A中注入了B
@Autowired
private B b;
}
@Component
public class B {
// B中也注入了A
@Autowired
private A a;
}
几个缓存:
private final Map2.1 获取A:getBean(a)singletonObjects = new ConcurrentHashMap<>(256); private final Map > singletonFactories = new HashMap<>(16); private final Map earlySingletonObjects = new HashMap<>(16); private final Set singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
此时的beanName是“a“ 先从单例池中找,此时肯定是找不到的,返回null。
isSingletonCurrentlyCreation方法是判断当前Bean是否在singletonsCurrentlyInCreation集合当中。此时也是没有的,返回false。那么就不会进第一个if。直接返回null值。
表示从缓存中获取不到 “a” 对应的Bean
因为上面没有获取到Bean,这里就要去准备创建一个Bean,进入getSingleton(beanName,singletonFactory)方法
首先从一级缓存中查找,没有,返回null。
beforeSingletonCreation(beanName),创建单例前的操作,将beanName(a)加入singletonsCurrentlyInCreation(该集合用户缓存当前正在创建bean的名称)
执行singletonFactory的getObject()方法获取bean实例,其实是调用createBean()方法。之后调用doCreateBean(beanName, mbdToUse, args)方法,真正创建A实例对象。
实例化A:createBeanInstance();
addSingletonFactory,在填充A的属性之前,会将创建Bean A的工厂放入到singletonFactories(三级缓存)中。
属性赋值:populateBean()
在属性填充之前,会先去获得属性值,但是此时的B对象并没有被实例化,所以需要先去实例化B才可以。此时递归的去调用getBean(b)构建B对象,再调用doGetBean()方法
和之前一样先调用getSingleton方法,4个集合中,都没有和“b“有关的缓存,所以返回null
进入getSingleton(beanName,singletonFactory)方法,将“b“ 放入到 singletonsCurrentlyInCreation 集合中
执行singletonFactory的getObject()方法获取bean实例,其实是调用createBean()方法。之后调用doCreateBean(beanName, mbdToUse, args)方法,真正创建B实例对象
和之前一样,在填充B的属性之前,会将创建Bean B的工厂放入到singletonFactories中
此时四个集合的状态
属性赋值:populateBean()
B的属性有A,也就是去获取A实例Bean。
代码又回来到AbstractBeanFactory# doGetBean
首先调用getSingleton 来从缓存中获取。进入getSingleton 看看能不能得到A的实例
获取到三级缓存中的工厂
调用对象工工厂的getObject方法来获取到对应的对象,其实调用getEarlyBeanReference()方法,(如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象)
同时将半成品对象放到二级缓存并将包装对象从三级缓存中删除掉
此时4个集合的状态:
afterSingletonCreation(name),创建单例后的操作,把singletonsCurrentlyInCreation标记正在创建的bean从集合中移除
addSingleton(beanName, singletonObject),把对象加入到单例缓存池中(所谓的一级缓存 并且考虑循环依赖和正常情况下,移除二三级缓存)
此时构成了一个完整的B,A属性填充完毕
afterSingletonCreation(name),创建单例后的操作,把singletonsCurrentlyInCreation标记正在创建的bean从集合中移除
addSingleton(beanName, singletonObject),把对象加入到单例缓存池中(所谓的一级缓存 并且考虑循环依赖和正常情况下,移除二三级缓存)
好的博客:Spring 为何需要三级缓存解决循环依赖,而不是二级缓存
面试必杀技,讲一讲Spring中的循环依赖
Spring什么时候创建代理对象?
正常Bean在生命周期的最后一步完成代理
涉及循环依赖的代理对象在实例化后创建,循环依赖调用getSingleton查看缓存时,会调用getEarlyBeanReference(),其中AOP的AbstractAutoProxyCreator.getEarlyBeanReference()方法也在此执行,但只有循环引用的对象为代理对象的时候才会进行动态代理
去掉第三级缓存的情况:
去掉第二级缓存的情况:
拿到ObjectFactory对象后,调用ObjectFactory.getObject()方法最终会调用getEarlyBeanReference()方法,getEarlyBeanReference这个方法主要逻辑大概描述下如果bean被AOP切面代理则返回的是beanProxy对象,如果未被代理则返回的是原bean实例。
由于去除了第二级缓存,所以不能二级缓存earlySingletonObjects中,只能通过每次调用来获取
但不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象
上一篇 Flink对接Kafka的topic数据消费offset设置参数
下一篇 Rabbitmq安装出错问题[Stack trace: ** (ArgumentError) argumenterror(stdlib 3.15.2) ]