您的位置:首页 > 编程语言 > Java开发

原来spring是这样处理循环依赖的

2020-06-26 04:29 375 查看

构造器循环依赖

场景: A的构造器依赖B,B的构造器依赖C ,C的构造器依赖A
Spring的处理:报错 BeanCurrentlylnCreationException

setter循环依赖

场景: A依赖B,B依赖C ,C依赖A 但是都是通过setter方法设置

Spring的处理:再创建A的时候会根据无参构造器构造A,然后暴露一个ObjectFactory用于返回A,同样的逻辑去构建B和C,当C构建完成时,可以通过A暴露的ObjectFactory完成C对A的依赖,最后完成循环依赖。

prototype 范围的循环依赖

Spring的处理:因为spring不缓存prototype范围的bean,所以无法按照2的逻辑提前构建,此时我们只有通过setAllowCircularReferences(false) 来禁用循环依赖

在此我们探究的是第二种setter循环依赖是怎么实现的

当我们谈论到循环依赖不得不又来再遛一遍bean的创建过程了,对与spring来说最核心的方法之一 getBean 可以让我们在当前容器中获取一个bean对象,这个对象比我们直接new出来的对象要丰满很多,因为它被spring赋予了很多特性,按我们常用的方式AbstractBeanFactory#getBean -> doGetBean 进入到我们此次重点关注的方法内

doCreateBean


在创建bean的过程中会去校验是否开启了循环依赖,其实进入此处的时候earlySingletonExposure这个条件中的当前bean是否是单例bean,和当前bean是否正在创建是恒为true,会不会进入循环依赖的唯一标识就是allowCircularReferences,spring是否开启了循环依赖,如果开启了循环依赖 那么再进行属性填充之前就会提前暴露一个ObjectFactory

getSingleton (beanName)


从这段源码不得不扯到三级缓存了,这还要感谢最近看的享学课堂的maybe老师,经过maybe的指导,才发现三级缓存的却设计的很巧妙,以普通开发者的思维只需要2个map就可以满足上图的需求,earlySingletonObjects的存在貌似没有必要,实际上这是因为我们通常工作中创建对象都是new一个对象,创建过程中不会涉及到很多复杂的逻辑,但是spring不一样,spring创建一个对象是十分繁琐的,每次创建对象都需要去校验,解析配置/属性信息,详情可以查看AbstractAutowireCapableBeanFactory#createBean 中调用的doCreateBean,所以spring的设计者设计了三级缓存的存在,对于单例bean而言 校验资源,解析配置 执行后置处理器等过程只需要执行一次,重复执行的话没有意义,所以当二级缓存中的ObjectFactory对象调用getObject() 获取一个半成品对象后直接将这个对象加入到三级缓存中待下次使用。此时这个ObjectFactory也丧失了存在的意义,如果这个对象不从singletonFactories中移除,那么spring容器会一直持有这个对象导致jvm不能对此对象进行垃圾回收。这里拿一个maybe讲的例子加深印象:

比如张三需要找个女朋友需要经历下面几步
1.加个微信
2.约个会
3.吃饭
4.看电影
5.确定关系
。。。
当学校放了寒假之后,张三和她女朋友都从家里回来了,这个时候张三想找他女朋友看个电影,那还需要重新走加微信,约会的过程吗,对于spring的三级缓存而言ObjectFactory干的事情就是1,2,3...
,而当已经确定关系了就等结婚了还需要重新走一遍前面的流程吗?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: