Spring的核心技术(七)---循环依赖

循环依赖

如果使用构造器注入的方法,就可能会创建一个无法解析的循环依赖的场景。

例如:类A通过构造器注入需要类B的一个实例,并且类B通过构造器注入也需要一个类A的实例。如果对类A和B做了这样的相互注入的配置,那么Spring的IoC容器会在运行时检查这种循环引用,并抛出BeanCurrentlyInCreationException异常。

一种可能的解决是修改某些类的源代码,通过Setter方法而不是构造器方法来注入依赖。或者避免使用构造器注入,只是用Setter注入。换句话说,虽然不推荐使用Setter方式来注入依赖,但这样可以配置循环依赖。

跟典型的场景(没有循环依赖)不同,循环依赖的两个Bean会强制其中的一个注入到另一个优先完全自我初始化的Bean中(这是典型的鸡生蛋,然后再蛋生鸡的场景)。

通常我们会相信Spring会做正确的事情,如在容器加载时,它会检查配置的问题,如引用了不存在的Bean和循环依赖。在实际创建Bean的时候,Spring会尽可能晚的来设置属性和解决依赖问题。这就意味着即使在Spring容器正常加载之后,也会产生对象创建不了或依赖不足等异常。例如相关的Bean会抛出不存在或无效属性之类的异常。这种方式导致某些配置问题延迟暴露,所以默认情况下ApplicationContext实现提前实例化单例模式的Bean。在实际使用相关Bean之前就创建这些Bean,会支付一些时间和内存的成本,但这样会在创建ApplicationContext时就发现配置问题,而不至于发现的较晚。这种默认的行为是可以重写的,以便让单例模式的Bean在需要时才实例化,而不是提取实例化。

如果没有循环依赖存在,在一个或多个合作用的Bean被注入到一个依赖Bean中时,每个合作用的Bean要完全配置在被注入的依赖Bean之前。这就意味着,如果Bean A依赖于Bean A,那么Spring的IoC容器在调用Bean A上的Setter方法之前要完全的配置Bean B。换句话说,实例化相关的Bean的时候(不是提取实例化单例),它所依赖的设置、以及相关的生命周期方法(如配置初始化方法或初始化Bean的回调方法)都要被调用。

展开阅读全文

没有更多推荐了,返回首页