Spring如何解决循环依赖问题

现象:

循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。

 

如何理解依赖?在spring中有:

(1)构造器循环依赖:结果:项目启动失败,发现了一个cycle

@Service
public class A {  
    public A(B b) {  }
}

@Service
public class B {  
    public B(C c) {  
    }
}

@Service
public class C {  
    public C(A a) {  }
}

 

(2)field属性注入循环依赖:结果:项目启动成功

@Service
public class A1 {  
    @Autowired  
    private B1 b1;
}

@Service
public class B1 {  
    @Autowired  
    public C1 c1;
}

@Service
public class C1 {  
    @Autowired  public A1 a1;
}

 

(3)field属性注入循环依赖(prototype):结果:项目启动失败,发现了一个cycle。

@Service
@Scope("prototype")
public class A1 {  
    @Autowired  
    private B1 b1;
}

@Service
@Scope("prototype")
public class B1 {  
    @Autowired  
    public C1 c1;
}

@Service
@Scope("prototype")
public class C1 {  
    @Autowired  public A1 a1;
}

 

现象总结:同样对于循环依赖的场景,构造器注入和prototype类型的属性注入都会初始化Bean失败。因为@Service默认是单例的,所以单例的属性注入是可以成功的。

 

分析原因:也就是在发现SpringIIOC的过程。

 

 

总结:有人问:为什么SingletonBeanFactory只是一个三级缓存,那么一级缓存和二级缓存有什么作用呢?

其实只要理解整个流程就可以切入了,Spring在初始化Singletion的时候大致可以分为几步,初始化——>设置值——>销毁,循环依赖的场景只有A——>B——>A这样的顺序,但是在并发的场景下,每一步在执行时,都有可能调用getBean方法,而单例的Bean需要保证只有一个instance,那么Spring就是通过这些个缓存外加对象锁去解决这类问题,同时可以省去不必要的重复操作。Sring的锁的粒度选择也是很厉害。

解决此类问题的关键就是要对SpringIOC和DI的整个流程了解,源码一般情况下不要求每一行代码都了解透彻,但是对于整个的流程和每个流程中在做什么事都需要了解,这样实际遇到问题才能可以很快的切入进行分析解决。

posted @ 2019-10-08 14:24  CHANGEMAX  阅读(745)  评论(0编辑  收藏  举报