依赖注入(    Dependency Injection
)的意思就是对象通过构造器函数参数,工厂方法的参数,或者成员属性,定义了对象的依赖对象;容器在创建该对象时会负责注入这些依赖。这个过程是控制反转的,即不是由即将创建的对象来管理自己的依赖的发现和实例化,而是有Spring容器来实现。  
在    Spring
中依赖注入有两种形式,第一种就是基于构造函数的注入,即通过调用构造函数,传入参数,也就是依赖来完成整个依赖注入流程;第二种就是基于    setter
方法的注入。  
构造函数的参数的匹配,要避免歧义,如指定类型,指定参数的次序等。如果是按照参数名字匹配,则必须开启    debug
模式进行编译,否则参数名字是不保留的。如果不想开启    debug
模式编译,则可以使用    @ConstructorProperties
注解。  
    setter
方法注入是先调用没有参数的默认构造函数构建对象,或者没有参数的静态工厂方法,实例化    bean
后,调用    setter
方法来将该对象注入。  
通过使用依赖注入,可以使代码更简洁,更好地实现对象之间解耦。另外,通过依赖注入管理的的对象是    POJO
类,可以更好地进行测试。  
最佳实践是通过构造器方法注入主要依赖对象,通过    setter
方法注入可选的依赖对象。虽然可以在    setter
方法上加上    @Required
注解来实现主要依赖对象注入,但一般还是推荐使用构造器注入必须的依赖。  
使用构造器注入,可以使得应用的组件作为不可变的对象,而且可以保证注入依赖是非    null
的。另外,构造器注入返回的是一个完整的初始状态的实例。但是,一般不推荐大量使用构造方法注入,如果出现这种情况,则说明代码需要重构。  
    setter
方法适合注入可选的依赖,这些依赖可能有默认值,而且在其他位置使用这些依赖时务必要进行    null
值检查。使用    setter
方法的一个好处是可以修改或者重新配置,或者需要时再注入。如基于    JMX MBean
的管理。  
首先    ApplicationContext
会被创建和初始化,会加载包括描述所有    bean
的元数据。这些配置元数据可以通过    XML
,    Java
代码或者注解来指定。  
对于每一个    bean
,它的依赖表现形式是成员属性,构造器参数,或者静态工厂方法的参数。在    bean
真正创建时,    Spring
容器会提供这些依赖的对象。这些参数可能是需要设置的默认值,也可能是另外一个    bean
的引用。  
    Spring
容器会验证每个    bean
的配置信息。并且在    bean
真正创建时才设置设置属性值或者参数值。  
在    Spring
中,单例作用域的    bean
会提前初始化,在    Spring
容器创建时就进行了实例化。对于其他的作用域的    bean
,则只在需要时才进行创建。之所以单例作用域的    bean
会被提前初始化,主要是为了解决依赖检查的问题,下文的循环依赖一节会详细说明。  
在    Spring
内部会构建一个创建    bean
的依赖图,按照这依赖关系来创建    Bean
。  
如果使用构造函数注入,则不能有循环依赖的情况。如    A
构造器依赖    B
,同时    B
也构造器依赖    A
。    Spring IoC
容器会在运行时检测到循环依赖,抛    BeanCurrentlyInCreationException
异常。一种解决办法是通过    setter
方法来解决循环依赖的情况。  
    Spring
会在容器加载时检测配置问题,如引用不存在或者循环依赖。    Spring
会在必要时才解析依赖,即尽可能晚的来解析依赖关系。延迟解析依赖可能导致后期请求获取对象时报错,如抛出一个异常,如丢失指定对象或者属性。这种配置的延迟的可见性导致的问题使得    ApplicationContext
的实现要求单例作用域的    bean
提前记性初始化。虽然会耗费内存和时间,因为并不是按需创建这些单例作用域的    bean
,但是可以在    ApplicationContext
创建时就可以发现配置问题。  
下文会介绍通过指定    bean
的可以通过配置来覆盖默认的行为,使得单例作用域的    bean
也是延迟初始化。  
如果没有循环依赖存在,则在注入依赖对象时,这些依赖的对象就已经初始化完成了。即如果    A
依赖    B
,则在    A
初始化时,    B
已经初始化完成了。也就是说,    Bean
是在相关依赖设置完成,并且相关的生命周期方法调用完毕后,才算是完成了初始化。  
默认情况下    ApplicationContext
是提前初始化单例作用域的    bean
,作为    ApplicationContext
初始化的一部分。这样可以尽快的发现配置问题。可以通过指定    bean
的    lazy-init="true"
,让    bean
在需要时才被初始化。  
在Spring中可以自动注入依赖,可以减少指定属性或者构造器参数,还可以随着配置对象的变化来更新注入的对象。
自动注入依赖的模式有:通过名称注入,通过类型注入,和通过构造器注入。