新人入住,请多多指点,感觉对您有帮助,请三连~~~,您的这小小举动,是对我最大的鼓励。
1、什么是循环依赖
1.1、官方解释
类A在构造函数中依赖于类B的实例,而类B的构造函数有依赖类A的实例。想这样配置类A和类B相互注入的话,SpringIOC容器会发现这个运行时的循环依赖,并且抛出BeanCurrentlyInCreationException、
1.2、图解
循环依赖是指,A依赖B,B依赖A,他们之间形成一个闭环。如图:
以上就是SpringIOC简单概念介绍,接下来,我们就从Spring源码层级去看下Spring是怎么通过三级缓存去解决循环依赖。
2、三级缓存解决循环依赖
这里的我画了一个流程图,方便新手去查看源码。(会的人可以略过)
入口从这里进
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
2.1、refresh()方法中一些方法含义
方法名 | 方法含义 |
prepareRefresh() | 准备上下文进行刷新 |
obtainFreshBeanFactory() | 告诉子类刷新内部Bean工厂 |
prepareBeanFactory() | 准备在此上下文中使用Bean工厂 |
postProcessBeanFactroy() | 允许在上下文中使用Bean工厂 |
invokeBeanFactoryPostProcessors() | 调用Bean工厂的后置处理器 |
registerBeanPostProcessors() | 注册Bean工厂的后置处理器 |
initMessageSource() | 初始化上下文消息源 |
initApplicationEventMulticaster() | 初始化上下文的事件多播 |
onRefresh() | 初始化特定上下文子类中的其他特殊Bean |
registerListeners() | 检查监听Bean并注册他们 |
finishBeanFactoryInitialization() | 实例化剩余的单例Bean |
finishRefresh() | 最后一步 发布相应的事件 |
2.2、三级缓存简介
三级缓存名称 | 类型 | 作用 |
singletonObjects | Map<String,Object> | 一级缓存,存放完整的Bean |
earlySingletonObjects | Map<String,Object> | 二级缓存,存放早期的Bean,为了判断是否存在循环依赖的关键缓存。 |
singletonFactories | Map<String,ObjectFactory<?>> | 三级缓存。 |
2.3、三级缓存工作原理
2.4、Spring5.1.x版本与Spring5.3.10版本的区别
看源码,我们能看出来,唯一的区别就是Spring5.3.10版本在加锁前,增加一个从二级缓存中获取一次Bean。
很明显,spring 在5.3.x版本中,对解决循环依赖的getSingleton方法进行了优化。后面我们再说,这样有什么好处。
我们来看下,classA 和classB的加载过程,如图
根据上面图,我们不难看出,类A在实例化之后,会去缓存中获取BeanA,并将BeanA放到了二级缓存中,然后进行属性赋值,发现A依赖了B,然后B也开始进行实例化B,并将BeanB放到了二级缓存中,然后进行属性赋值,这时发现B依赖A,然后A又开始重复走,当A从缓存获取的时候,从一级缓存是肯定获取不到的,因为BeanA没有初始化成功。然后A从三级缓存中拿出来放入到二级缓存中,然后又进行属性赋值,这时发现A依赖C,然后C又开始doCreateBean,然后C在属性赋值的时候,发现C依赖A,然后A又开始rdoCreateBean,这个时候A已经在二级缓存中了,所以直接从二级缓存中返回Bean。
我所能想到的这个场景能实现Spring5.3.x的优化的思想。
我们发现加锁是一个Synchronized锁,他是一个重量级锁。
3、总结
以上就是SpringIOC在采用三级缓存来解决循环依赖的具体实现。
其实,我们可以看源码能发现,二级缓存其实也足以解决循环依赖的问题,但是网上好多人都在说,三级缓存存在的作用是解决动态代理问题,其实这个说法也有道理。
但是我的理解,你看
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {}
这个接口,我们可以去实现这个接口,然后去重写里面的方法。所以,我觉得,Spring采用三级缓存的作用其实是为了更好的扩展,更好的维护性作用,也是Spring底层源码的设计思想。
乾坤未定,你我皆是黑马!!!!