spring相互依赖怎么解决_被问到Spring循环依赖怎么解决?秀给面试官看!内附图解...

本文探讨了Spring框架如何处理单例Bean的循环依赖问题,指出Spring通过内部的三级缓存机制来解决这个问题。介绍了在构造器上不支持循环依赖,并通过一个简单的twosum问题类比,解释了循环依赖的本质。文章还提到了解决循环依赖的一种类似twosum的解决方案,即使用HashMap进行快速查找和存储。
摘要由CSDN通过智能技术生成

不知道最近有没有被一道Java面试题刷爆朋友圈,Spring框架的循环依赖如何解决。我收到了不少粉丝的提问,在了解到之后,也去网上查询了一些资料,自己也询问了身边的同事,总结出以下几个方面,今天就和我来看一看吧~

bd73c9cb4a24f8eff0e3db6f01ee8fad.png

寻常情况下,如果问Spring内部怎么去解决循环的依赖性,一定是单默认的单例Bean中,属性互相引用的场景。假设几个Bean之间的互相引用,甚至循环依赖自己。

2908e0bb21f0608ac3b96bbaeaffa2e9.png
13df04ccc74240f0cf78a6bd2186001b.png

根据上面的两个图,我们先说一下循环依赖与原型的场景是不互相支持的,通常会走到AbstractBeanFactory类中下面的判断,然后反馈回异常问题。

if (isPrototypeCurrentlyInCreation(beanName)) {    throw new BeanCurrentlyInCreationException(beanName);  } 

原因其实并不难,如果要创建一个新的A就会发现需要注入原型字段B,当创建新的原型字段B时又发现需要新的A。这就很尴尬了,禁止套娃!总不能靠猜去判断先是StackOverflow还是OutOfMemory?这也太难了吧~

所以Spring怕你猜起来困难,就非常贴心的出现了BeanCurrentlyInCreationException。真不愧是我最爱的框架。

在基于在构造器上的循环依赖,这就不必再多说了,官方文档有很明显的指示,想让构造器注入去支持循环依赖?这就不可能了,改代码吧······

那么默认单例的属性注入场景,那么Spring对循环依赖是如何支持的呢?

Spring解决循环依赖

这时候我们就不得不说到Spring的内部了,它内部维护了三个Map,这是什么?就是我们常说的三个缓存级别。这是为了让更好理解,其实并没有官方名字坐实这个三级缓存的概念。不过这不重要,接着看就是了。

在Spring的DefaultSingletonBeanRegistry类中,你就会发现它的上面有三个Map:

1.singletonObjects。这个或许是我们最熟悉的部分了,我们通常叫它:单例池,容器,它其实就是缓存创建完成单例Bean的地方。

2.singletonFactories。用来映射创建Bean的原始工厂。

3.earlySingletonObjects。它用来映射Bean的早期引用,这意思就是Map里的Bean并不完整,与其称之为Bean,倒不说它只是一个Instance.

再往后的两个Map就更像是一个“垫脚石”了,创建Bean时用了一下,用完就清理了。

循环依赖的本质

了解本质之后才能知道如何解决,刚才说了Spring如何处理循环依赖,首先,我们跳出“阅读源码”的思维,举个例子,如果让你实现下面的功能,你会如何去做?

1.将指定的一些类实例为单例

2.类中的字段同样实例为单例

3.必须支持循环依赖

假设类A是存在的,那么

public class A {      private B b;  }  // 类B:  public class B {      private A a;  } 

看到了吗?其实就是让你模仿一下Spring,假设A和B被修饰,而且类之间的字段假设是通过Autowired修饰,然后放到Map里面,经过处理之后再放到Map里面。

27cfcd032aa0ae635b6f1a75948853bd.png

其实上述并不是“Spring如何去解决循环依赖”而是循环依赖的基本本质,其实在网上可以搜索到很多例子,完全可以去百度一下看一看,这可以让你不在阅读的泥潭里陷得太深进而忽略了问题本质,如果实在是看不懂,逆推Spring的实现原因效果会好很多。

问题的本质竟然在于two sum?

说到这里有没有觉得似曾相识?好像在什么时候见过似的,没错,和two sum的解题是很相似的。什么?你不知道two sum?two sum是刷题网站leetcode序号为1的题,也就是大多人的算法入门的第一题。经常有梗对于这个two sum,感兴趣的可以去看看。咳咳,跑题了,我们再回来

问题的内容是:先给你规定数组,再给定一个数字。再返回到数组里面允许通过相加得到指定数字的两个索引。我们举个例子,给定nums = [2, 7, 11, 15], target = 9 那么要返回 [0, 1],因为2 + 7 = 9这道题的优解是,一次遍历+HashMap:

class Solution {      public int[] twoSum(int[] nums, int target) {          Map map = new HashMap<>();          for (int i = 0; i < nums.length; i++) {             int complement = target - nums[i];              if (map.containsKey(complement)) {                  return new int[] { map.get(complement), i };              }              map.put(nums[i], i);          }          throw new IllegalArgumentException("No two sum solution");      }  } 

这个时候就需要先去Map中寻找我们需要的数字,如果没有,那么就将数字先保存到Map里面,再寻找到需要的数字时,一起返回即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值