Spring如何处理循环依赖问题
什么是循环依赖:
就是多个bean之间相互依赖,形成了一个闭环,比如beanA需要引用BeanB,BeanB需要引用BeanA,形成循环关系。一般默认在单例模式中,属性相互影响的场景。(多个对象之间存在循环的引用关系,在初始化过程当中,就会出现“ 先有蛋还是先有鸡 ”的问题)
依赖注入的两种方式:
-
构造方法注入【不适合解决循环依赖】 构造器循环依赖是无法解决的,如果想让构造器支持循环依赖,是不可能的。
-
set方法注入
spring bean发生循环依赖有三种形式:互相依赖、三者之间及其以上的依赖、自我依赖。
如何解决循环依赖:
-
使用@Lazy注解:解决构造方法造成的循环依赖问题
@Lazy注解: 当@Lazy 放在类上,表示在启动的时候不会创建bean对象,当使用的时候才会创建; 当@Lazy 放在@Bean注解的方法上,表示在启动的时候不会创建bean对象,当使用的时候才会创建; 当@Lazy 放在@Autowired注解的属性上, 并不会直接给属性赋上真正的值,只是会赋值一个代理对象,当真正使用到这个属性的时候,才回去容器中找到一个符合的对象。在使用的时候,也会先执行代理对象的逻辑,然后再是真正bean对象的逻辑; 使用场景:循环依赖的时候可以在循环依赖的对象加上@Lazy注解; 写在方法或者方法参数前面上,效果和写在属性上、一样的,开始注入的只是代理对象,当真正调用的时候才会调用对应对象的逻辑 写在构造方法或者构造方法参数前面上,同上。
-
使用三级缓存
利用缓存机制解决循环依赖问题,spring设计了三级缓存解决循环依赖的问题,分别是一级缓存:singletonObjects;二级缓存:earlySingletonObjects;三级缓存:singletonFactories;
一级缓存:singletonObjects,存放初始化后的单例对象;
二级缓存:earlySingletonObjects,存放实例化,未完成初始化的单例对象(未完成属性注入的对象);
三级缓存:singletonFactories,存放ObjectFactory对象(代理对象);
三级缓存之间逐级取,流程如下:
1、getBean()获取实例,Spring首先从一级缓存singletonObjects中获取;
2、如果获取不到,就从二级缓存earlySingletonObjects中获取,如果还是获取不到意味着bean没有实例化;
3、这时singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取;(代理也是从三级缓存生产的)
4、如果从三级缓存中获取到就从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存;
5、这个bean存在会等待下一次轮寻的时候去赋值(解析@Autowared,@Resource)注解等,属性赋值完成后,将bean存入一级缓存;
解决循环依赖简单的流程图:
转载至:
https://www.cnblogs.com/huangtiing/p/16743815.html
https://blog.csdn.net/DQWERww/article/details/126128229
https://blog.csdn.net/yaoyaochengxian/article/details/118636958
标签:缓存,对象,Spring,bean,依赖,三级,循环 From: https://www.cnblogs.com/galo/p/16965829.html