Spring 循环依赖感悟

Fred  2021年9月23日 04点20分

循环依赖的本质其实是 bean 在创建过程中反过来被引用

  1. singletonObjects 对应的是工厂模式很好理解。
     
  2. singletonFactories 起到孵化作用,未发生循环依赖时正常孵化存入 singletonObjects。发生循环依赖时被迫提前孵化存入 earlySingletonObjects。对于后者目前了解到的有两种形态,一种是未发生 AOP 时原样孵化,另一种是 AOP 孵化。读者可以思考下为啥是个工厂。
     
  3. earlySingletonObjects 的存在和 AOP 有关。org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator 中的 wrapIfNecessary 函数中的这段代码实现了对原始类的代理(cglib yyds, 接口代理出来的与原来的类类名不一致)。

    那么思考这种情况:A 依赖 B, B 依赖 A 和 C,C 依赖 A。

    简而言之就是一次 resolve 中 A 先后被依赖多次,如果不采取措施这个 wrapIfNecessary 函数就会被触发多次,(map 键值对容器中表现为同键之后的值覆盖之前的值)于是 b 拿到一个 a 的代理对象,c 拿到另一个 a 的代理对象,混乱发生!解决方法之一就是缓存第一个(有且仅有一个)代理对象避免再次进入 wrapIfNecessary 函数,于是体现出 earlySingletonObjects 这个 map 存在的价值,里面存放了这些代理对象,注意这个函数在不发生代理时直接返回原来的 bean 也会被存进来,主要价值还是体现在缓存正确的代理对象上。

wrapIfNecessary 函数

// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
   this.advisedBeans.put(cacheKey, Boolean.TRUE);
   Object proxy = createProxy(
         bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
   this.proxyTypes.put(cacheKey, proxy.getClass());
   return proxy;
}

  • 无论是从 singletonFactories -> singletonObjects 还是 singletonFactories -> earlySingletonObjects -> singletonObjects 最终还是到了 singletonObjects 做成了工厂模式,或许这就是大动脉吧。

     
  • 学习了一些文章以后遇到了一个问题,依赖对象和被依赖对象的注入方式会不会影响最终的 resolve 结果。答案是肯定会的,如果构造都还没构造出来就被引用了就会报错(目前是这样的吧,未来期待有改变哈哈 - -)。

     
  • 个人简单测试中 earlySingletonObjects 这个 map 使用的概率还是蛮小的,源码注释上写了如果两个类 "纠缠不清" 程序员就有必要主动想想能不能做点什么帮帮他们。

PS:个人认为三级缓存的说法并不是十分合理,因为这其实三个缓存 map 不是严格的层级关系。这里杠一杠,两级缓存行不行? 行啊当然行,一个 map 都给你搞定,没规定一个 map 里不能套别的 map 啊 ......

测试模型

spring.springframework 5.3.3

图中的红字分叉可以简单理解为是否过早的被引用,这里的 proxy 是广义的,即直接返回原对象也看成是一种无作为的代理。AOP 为 xml 或者注解配置,记得继承接口 切 接口的实现方法。

学习肯定会有误区,第一篇文章风格也随意。如有技术认知方面的错误或者文本编辑方面的建议都欢迎交流,日记心态纯手敲原创。

附简单断点调试图

 谢谢您的浏览,如有纠正或者建议感激不尽。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值