有两个Bean——a和b,而这两个Bean经过各自的构造函数互为依赖项,那么Spring容器就没法实例化这两个Bean:函数
public class A{this private B b;spa public A(B b){ci this.b=b;作用域 }io }table
public class B{class private A a;容器 public B(A a){配置 this.a=a; } } |
<bean id=”a” class=”com.lizhen.A”> <constructor-arg ref=”b” /> </bean>
<bean id=”b” class=”com.lizhen.B”> <constructor-arg ref=”a” /> </bean> |
这是由于当第一个Bean被建立时,期待第二个Bean被注入到自身。然而,此时第二个Bean也处于建立阶段,而且也期待第一个Bean做为本身的依赖项。这样就会在应用程序中致使BeanCurrentlyCreationException。但另外一方面,Setter注入可以处理此类循环。虽然Spring经过使用Setter注入容许循环依赖,但对于那些有循环依赖的Bean而言,Spring的不少其余功能将没法使用。所以,通常来讲,不建议在配置中使用循环依赖。
Spring容器的启动过程大体可分为两个主要阶段:
① 容器处理配置元数据并创建元数据中存在的Bean定义,在该过程当中还会对这些Bean定义进行验证。例如,检查是否向<property>和<constructor—arg>元素提供正确的Bean引用,等等。然而,在该步骤中,Bean并无被建立,相关的属性也没有被注入。
② 首先完成Bean的建立,而后完成依赖注入。但实际上,并非全部的Bean都被建立;在容器启动期间,仅建立了无状态做用域的Bean。Bean的建立实际触发了一连串其余依赖Bean的建立,而这些依赖Bean又会触发它们的依赖项的建立,以此类推。
一个Bean在被彻底建立且本身的依赖项被注入以前是不会做为一个依赖项被注入到其余Bean中去的。所以,必须确保被注入某一Bean中的Bean依赖项被彻底配置且能够在目标Bean中引用。(惟一类外的是上面所说的循环依赖)
重写Spring容器中的Bean定义是可能的。每一个Bean都有身份(即id名),而Bean的名称定义了本身的身份。若是建立了一个Bean定义,而该Bean的名称已经赋予了其余Bean定义,那么第二个定义将重写第一个定义。
若是Bean a直接或间接依赖Bean b,那么能够确定Spring容器将首先建立Bean b。然而,若是两个Bean定义彼此之间没有直接或间接依赖,那么Bean建立的顺讯就有Spring容器内部肯定。此时,没法确保Bean b始终在Bean a以前被建立。有时,虽然Bean之间没有彼此依赖,但他们却须要彼此之间有一个特定的建立顺序。例如,一个执行JVM级别初始化的Bean必须在其余Bean以前被建立,由于这些Bean在被初始化以前必须先完成JVM级别的初始化。在此类状况下,能够在基于XML的配置中经过使用<bean>元素的depends-on特性来指定Bean b 在Bean a以前被建立。
<bean id=”a” class=”com.lz.A” depends-on=”b,c” />
能够在depends-on特性中列出多个Bean名称。同时,在Bean析构阶段和Bean初始化阶段,depends-on特性也扮演了很是重要的角色。只有在无状态Bean的状况下,当该Bean使用了depends-on特性时,depends-on特性中所列举的Bean才被销毁。
做用:指定的Bean被建立以后才会建立本类,不然就不会建立本类。
有时,并无必要显示地在Bean定义中定义依赖项;可让Spring容器自动地向Bean中注入依赖项。该过程成为自动装配。
自动装配有三种模式:byType、byName和cinstructor
byType模式:
Spring首先经过Java反射查看Bean定义中的类,以便研究定义中的属性,而后尝试将容器中可用的Bean注入与器类型相匹配的属性。该注入操做主要是经过调用这些属性的Setter方法来完成的。例如:
<bean id=”a” class=”com.lz.A” autowire=”byType” />
<bean id=”b” class=”com.lz.B” />
若是有多个Bean实例适合自动装配到某一个特定的属性,那么依赖注入将会失败。此时须要为Spring容器提供帮助,以便肯定注入哪一个Bean实例。其中一种解决办法是从自动装配的候选Bean中进行过滤,并注入剩下的Bean。为此,可使用<bean>元素的autowire-candidate特性:
<bean id=”a” class=”com.lz.A” autowire=”byType” />
<bean id=”b” class=”com.lz.B” autowire-candidate=”false” />
<bean id=”c” class=”com.lz.C” />
byName模式:
上边状况的另一种解决方法就是用byName自动装配模式,这种状况下,容器尝试将属性名与Bean名称进行匹配,并注入匹配的Bean。
<bean id=”a” class=”com.lz.A” autowire=”byName” />
<bean id=”b” class=”com.lz.B” />
在Spring容器中没有候选Bean是将不会注入任何Bean,其默认属性值保持不变。
constructor模式:
该模式相似于byType模式,但在使用constructor模式时,Spring容器尝试找到那些类型与构造函数参数相匹配的Bean。一样,若是针对某一参数有多个候选Bean,Spring没法注入该参数。