循环依赖
2022-10-14 09:14:52 0 举报
Spring依赖注入所解决的循环依赖问题
作者其他创作
大纲/内容
Bean B
getBean()
实例化
singletonFactories#三级缓存添加
无
三级缓存
纯洁A
纯洁对象
拿出三级缓存的函数式
循环依赖的出现
@Componentpublic class BeanB { private String name; @Autowired private BeanC beanC;}
registeredSingletons#已经注册过的单例池添加
C依赖A
这时寻找A,在三级缓存拿出来执行
B依赖A
@Componentpublic class OrderService {@AutowiredUserService userService;@Asyncpublic void test(){System.out.println(userService);}}
Bean A
二级缓存中
@Componentpublic class OrderService {@AutowiredUserService userService;@Transactionalpublic void test(){System.out.println(userService);}}
有
earlySingletonObjects#二级缓存删除
构造方法导致的循环依赖解析
@Async 会生成一个新的代理对象,不同的对象,为什么要抛错?:因为赋值给B对象的A属性和Async生成的代理对象不一样,也就是放在单例池的对象跟赋值给B对象的A属性不一样解决方法:Lazy懒加载,在属性赋值B时,直接生成一个代理对象赋值给B。当调用的时候,直接执行代理对象的方法,然后通过name去单例池去拿B出来(此时B已经创建好了)
添加lambda表达式
判断缓存是否存在
二级缓存是否有
原型Bean情况下的循环依赖解析
初始化
一级缓存是否存在
代理对象 A
总结
放入缓存addSingleton
@AutowiredB b
一级缓存
@Componentpublic class BeanA { private String name; @Autowired private BeanB beanB;}
循环依赖
singletonFactories#三级缓存删除
只用二级缓存完全可以解决循环依赖只用二级缓存解决循环依赖问题:1.耦合 2.多线程读取性能问题
bean B
singletonObjects#一级缓存添加
实例化后就放入一级缓存
判断是否出现循环依赖且是否支持循环依赖
@Component@Scope(\"prototype\")public class OrderService { @Autowired UserService userService; public void test(){ System.out.println(userService); }}
属性填充解析@Autowired
@Component@Scope(\"prototype\")public class UserService { @Autowired private OrderService orderService; public void test(){ System.out.println(orderService); }}
判断是否提前AOP
无,且出现循环依赖
从singletonFactories根据beanName得到一个ObjectFactory,然后执行ObjectFactory,也就是执行getEarlyBeanReference方法,此时会得到一个A原始对象经过AOP之后的代理对象,然后把该代理对象放入earlySingletonObjects中,注意此时并没有把代理对象放入singletonObjects中,那什么时候放入到singletonObjects中呢?我们这个时候得来理解一下earlySingletonObjects的作用,此时,我们只得到了A原始对象的代理对象,这个对象还不完整,因为A原始对象还没有进行属性填充,所以此时不能直接把A的代理对象放入singletonObjects中,所以只能把代理对象放入earlySingletonObjects,假设现在有其他对象依赖了A,那么则可以从earlySingletonObjects中得到A原始对象的代理对象了,并且是A的同一个代理对象。当B创建完了之后,A继续进行生命周期,而A在完成属性注入后,会按照它本身的逻辑去进行AOP,而此时我们知道A原始对象已经经历过了AOP,所以对于A本身而言,不会再去进行AOP了,那么怎么判断一个对象是否经历过了AOP呢?会利用上文提到的earlyProxyReferences,在AbstractAutoProxyCreator的postProcessAfterInitialization方法中,会去判断当前beanName是否在earlyProxyReferences,如果在则表示已经提前进行过AOP了,无需再次进行AOP。对于A而言,进行了AOP的判断后,以及BeanPostProcessor的执行之后,就需要把A对应的对象放入singletonObjects中了,但是我们知道,应该是要把A的代理对象放入singletonObjects中,所以此时需要从earlySingletonObjects中得到代理对象,然后入singletonObjects中。
放入
删除
无,返回NULL
二级缓存
@AutowiredA a
@Componentpublic class OrderService { @Autowired UserService userService; public OrderService(UserService userService) { this.userService = userService; } @Async public void test(){ System.out.println(userService); }}
addSingletonFactory
纯洁B
没有
一级缓存是否有
判断缓存是否有A
A依赖B
这时的A就跟注入B的A对象不一样了
生成
B依赖C
代码耦合
构造方法的循环依赖无法解决,没法生成对象B要生成对象要依赖A,而A生成对象则要依赖B,两者拿不到无法创建
earlySingletonObjects(二级缓存):缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整生命周期的bean。
font color=\"#f44336\
这里一定能拿到A
singletonObjects(一级缓存):缓存经过了完整生命周期的bean
@Componentpublic class BeanB { private String name; @Autowired private BeanA beanA;}
如果进行了AOP,创建代理对象
创建代理对象A
执行得到对象放入
判断缓存是否有B
singletonFactories(三级缓存):缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖(当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。
二级缓存是否存在
用一级缓存解决循环依赖问题:B依赖的A和最终的A不是同一个对象。如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP产生了一个代理对象,此时就会出现,对于A而言,它的Bean对象其实应该是AOP之后的代理对象,而B的a属性对应的并不是AOP之后的代理对象,这就产生了冲突。
@Async情况下的循环依赖解析
@Componentpublic class BeanC { private String name; @Autowired private BeanA beanA;}
@Transaction情况下的循环依赖解析
三级缓存利用函数接口,将createBean和getBean的逻辑解耦因为二级缓存也能解决循环依赖,但是需要创建bean的相关逻辑在getsingleton中只有在出现了循环依赖的情况,才会执行lambda表达式,才会进行AOP,也就说只有在出现了循环依赖的情况下才会打破Bean生命周期的设计
一级缓存
对象
earlyProxyReferences:它用来记录某个原始对象是否进行过AOP了。
0 条评论
下一页