Spring循环依靠详解

打印 上一主题 下一主题

主题 990|帖子 990|积分 2974

一、什么是循环依靠

   

   

   
        在Spring框架中,循环依靠是指两个或更多的Bean相互间直接或间接地依靠对方的情况。这种依靠关系大概导致Bean的实例化过程中出现问题,但Spring通过其内部的处理机制可以或许解决某些范例的循环依靠。

   
        简单的说就是A依靠B,B依靠C,C依靠A如许就构成了循环依靠。

   二、循环依靠的3种情况

   1. 构造器循环依靠

   
        当Bean通过构造器参数注入其他Bean,并且存在循环依靠时,Spring无法解决这种依靠。这是由于Bean的实例化必要依靠于尚未创建完成的其他Bean,从而导致死锁。

  
  1. public class StudentA {
  2.     private final StudentB studentB;
  3.     public StudentA(StudentB studentB) {
  4.         this.studentB = studentB;
  5.     }
  6. }
  7. public class StudentB {
  8.     private final StudentA studentA ;
  9.     public StudentB(StudentA studentA) {
  10.         this.studentA = studentA;
  11.     }
  12. }
复制代码
  

   2. 原型(prototype)模式下的setter注入循环依靠

   
        循环依靠两边 scope 都是 prototype 的话,也会循环依靠失败,代码如下:

  
  1. @Service
  2. @Scope("prototype")
  3. public class AService {
  4.     @Autowired
  5.     BService bService;
  6. }
  7. @Service
  8. @Scope("prototype")
  9. public class BService {
  10.     @Autowired
  11.     AService aService;
  12. }
复制代码
  
        两者的区别是:有状态的bean都使用Prototype作用域,无状态的一样平常都使用singleton单例作用域。

   
        scope 为 prototype 意思就是每次请求都会创建一个新的实例对象,不用缓存里的。那么 AService 必要 BService,以是就去现场创建 BService,结果 BService 又必要 AService,继续现场创建,AService 又必要 BService...,以是终极就陷入到死循环了。

   
报错信息:

   

   

   

   3. 单例(singleton)模式下的setter注入循环依靠

   
        以上两种的循环依靠Spring并没有解决,必要开发者举行相应的设计调解或使用其他的依靠注入策略。但是单例模式下的setter注入循环依靠,Spring可以或许解决。

   
Spring的Bean实例化过程中会使用一个三级缓存机制:

   

  • 一级缓存(singletonObjects):存储已经完全初始化的单例Bean。
  • 二级缓存(earlySingletonObjects):存储尚未完全初始化的Bean,即已经实例化但尚未完成属性填充的Bean。
  • 三级缓存(singletonFactories):存储Bean的工厂对象,该对象可以创建Bean的实例并将其放置在二级缓存中。
   
当Spring检测到循环依靠时,它不会等待所有依靠都初始化完成,而是将Bean的工厂对象提前暴露给其他正在创建的Bean。如许,即使Bean尚未完成初始化,其他Bean也能引用它,从而打破了死锁状态。

   

   
懒加载解决循环依靠:

   
        在某些情况下,可以使用@Lazy注解来耽误Bean的初始化,从而避免循环依靠

       public class BeanA {   
@Autowired   
    @Lazy   
private BeanB beanB;   
}   
   
public class BeanB {   
@Autowired   
private BeanA beanA;   
}      

   三、三级缓存

   
        Spring可以或许轻松的解决属性的循环依靠正式用到了三级缓存,在AbstractBeanFactory中有具体的注释。

   

   

   

  • 一级缓存:singletonObjects,存放完全实例化属性赋值完成的Bean,直接可以使用。
  • 二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean
  • 三级缓存:singletonFactories,三级缓存,存放实例化完成的Bean工厂。
   1.getSingleton(beanName):源码如下:

   

   

   
从源码可以得知,doGetBean最初是查询缓存,一二三级缓存全部查询,如果三级缓存存在则将Bean早期引用存放在二级缓存中并移除三级缓存。(升级为二级缓存)

   2. addSingletonFactory:源码如下

   

   

   

   
从源码得知,Bean在实例化完成之后会直接将未装配的Bean工厂存放在三级缓存中,并且移除二级缓存

   

   3. addSingleton:源码如下:

   

   

   
Bean添加到一级缓存,移除二三级缓存。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

刘俊凯

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表