Spring 是如何解决循环依赖的?
2020-12-07 13:56:18 1 举报
Spring是如何解决循环依赖的?
作者其他创作
大纲/内容
A成熟
实例化
getBeanA@AutowiredB b
return BeanA
A依赖B
返回给B
没有
什么是循环依赖?
加入二级缓存
return
早期A
早期B
No
B依赖A
#增加一个出口这样解决循环依赖可用吗?
createBeandoCreateBean实例化属性赋值...省略
出口获取
属性赋值解析@Autowired
二级缓存&正在创建
作者:一角钱技术(org_yijiaoqian)内容:Spring 是如何解决循环依赖的?
加入一级缓存
class BeanB { @AutoWired BeanC c; }
class BeanB { @AutoWired BeanA a; }
getBeanB@AutowiredA a
三级缓存
getBean(b)
1.getBean(B)
add到一级缓存remove 二三级缓存
2.goGetBean(A)
有
使用三级缓存解决循环依赖才完美
放进
加入三级缓存
一级缓存
二级缓存
在这里创建动态代理好像能解决,但是初始化的创建proxy将没有存在的意义。正确应该当Bean是循环依赖中才创建动态代理。正常Bean依然在初始化创建,但是怎么判断当前Bean处于循环依赖呢?
闭环
创建proxy的逻辑
什么情况下会出现循环依赖?
7.属性赋值
线程1
8.初始化
返回给A
getBean(a)
put
加锁解决一级缓存循环依赖问题
class BeanA { @AutoWired BeanB b; }
1.getBean(A)
singletonObjects.get(beanName)
这里会阻塞,直到线程1走完线程1走完二三级缓存都没了最后return null
初始化创建动态代理
2.goGetBean(B)
此时线程二进来getBean(A)...
此时一级缓存中已经有了
正
Nice! 完美!
发现依赖A
6.实例化
用一级缓存解决循环依赖问题的是:无法保证在多线程下的一级缓存Bean的完整性解决 :加锁
return BeanB
此时二三级缓存都没了 锁才是否
创建proxy
只有在这里才能判断当前Bean是否循环依赖中。关键是怎么在这里调用创建动态代理的代码呢?直接拿过去?不不不,这样会把创建的饿逻辑和获取的逻辑强耦合,Spring不会写这么烂的代码,创建Proxy本身就属于创建Bean的逻辑。有办法解决,可以加一个缓存,将创建proxy的逻辑防止缓存中,什么?存代码?这么存,我们只知道存值,可以用函数接口存嘛
多线程在创建时怎么避免获取到不完整Bean
线程2
addSingleton(A)add到一级缓存remove 二三级缓存
B依赖C
这里虽然增加了一个出口,但是一级缓存是在这个闭环外面,所以依然存在死循环
虽然加锁解决了多线程问题,但是性能很差,如果A已经创建好了,A只需要读取Bean,是不是也要被阻塞。但是,由于早期Bean和完整Bean都存储在一级缓存,为了避免读取到早期不得不把读取一级缓存也锁起来。
A
B
class BeanC { @AutoWired BeanA a; }
OK. 二级锁完美解决循环依赖问题+多线程读取不完整Bean的性能问题现在出现新问题,如果A使用了AOP,那么它需要创建动态代理对象,但是创建动态代理对象是在初始化
发现依赖B
不要激动,还不完美:1. 创建Bean的创建结束后应该移除二三级缓存2. 你考虑过一级缓存的感受妈?? A如果Aop,一级缓存存的还不是proxy啊!3. 多线程同时创建A时,A是不是会创建2次,正常是不是第二个线程应该获取第一个线程创建好的。想不想知道这些问题这么解决的?总结:一级缓存能不能解决循环依赖:如果只有1级缓存解决循环依赖也是可以的,只不过性能最低、耦合性、扩展性都很差,二级缓存能不能解决循环依赖:可以,但是aop的动态代理会重复创建构造函数下的循环依赖能不能解决我就问你,我们现在在这属性下解决循环依赖的关键是什么?出口对不对,这个出口是什么?是不是必须要返回实例给我啊,构造函数出现循环依赖连实例都得不到这么解决循环依赖多里Bean能不能解决循环依赖?多例Bean不会走getSingleton,也就不会保存一级缓存并且也不会保存三级缓存,所以多例Bean根本不会使用缓存,不使用缓存怎么解决循环依赖怎么解决Bean在多线程并发出现的读取到不完整问题,双重检测锁(double checked locking)
0 条评论
下一页