简介

一个典型的企业应用程序不包含一个对象(或bean在Spring的说法)。即使是最简单的应用程序有几个对象,共同努力,目前终端用户眼中一个连贯的应用程序。这在下一节解释了如何从定义的bean定义独立,完全实现应用程序对象协作来实现一个目标


1.1 Dependency injection

依赖注入(DI)是一个过程,对象定义它们的依赖项,也就是说,他们处理的其他对象,只能通过构造函数参数,参数工厂方法或对象实例上设置的属性构造或后从工厂方法返回。然后容器注入这些依赖项时创建bean。这个过程从根本上是反,因此得名控制反转(IoC),控制实例化bean本身或位置的依赖自己的类,通过使用直接施工或服务定位器模式。

代码与DI清洁原理和分离对象时更有效的提供与他们的依赖性。对象不查找其依赖性,不知道位置或类的依赖关系。这样,你的类更容易测试,特别是当依赖接口或抽象基类,它允许使用存根或模拟实现单元测试。

DI存在于两个主要的变体,Constructor-based依赖注入和Setter-based依赖注入。

Constructor-based dependency injection


Constructor-based DI容器实现的调用构造函数的参数,每个代表一个依赖项。 调用一个静态工厂方法与特定的参数构造bean几乎是等价的,和这个讨论将参数构造函数和静态工厂方法类似。 下面的示例显示了一个类,只能dependency-injected构造函数注入。 注意,这个类没有什么特别之处,它是一个POJO,没有依赖于容器特定的接口,基类或注释。

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on a MovieFinder
    private MovieFinder movieFinder;

    // a constructor so that the Spring container can inject a MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...

}



Constructor argument resolution


构造函数参数分辨率匹配时使用参数的类型。 如果不存在潜在的歧义在bean定义的构造函数参数,然后的顺序构造器参数中定义bean定义这些参数的顺序提供给适当的构造函数实例化bean时。 考虑下面的类:

package x.y;

public class Foo {

    public Foo(Bar bar, Baz baz) {
        // ...
    }

}




不存在潜在的歧义,假设Bar类和Baz类继承并不相关。 因此以下配置工作正常,您不需要显式地指定和/或构造函数参数索引类型的< constructor-arg / >元素。


<beans>
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
    </bean>

    <bean id="bar" class="x.y.Bar"/>

    <bean id="baz" class="x.y.Baz"/>
</beans>



当另一个bean引用,类型是已知的,和匹配可能发生(与前面的示例一样)。当使用一个简单的类型,如<vaule> < /vaule>,春天不能确定值的类型,因此无法匹配的类型没有帮助。考虑下面的类:

package examples;

public class ExampleBean {

    // Number of years to calculate the Ultimate Answer
    private int years;

    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }

}



在前面的场景中,容器可以使用类型匹配的简单类型如果你显式地指定构造函数参数的类型使用type属性。

例如:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>



使用索引属性来指定显式地构造函数参数的指数。

例如:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>


除了解决多个简单的模糊值,指定一个索引解决歧义,相同类型的构造函数有两个参数。 注意,theindex是0。

You can also use the constructor parameter name for value disambiguation:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateanswer" value="42"/>
</bean>



package examples;

public class ExampleBean {

    // Fields omitted

    @ConstructorProperties({"years", "ultimateAnswer"})
    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }

}



Setter-based dependency injection


Setter-based DI容器实现的调用setter方法在bean调用无参数构造函数或无参数静态工厂方法实例化bean。


下面的示例显示了一个类,只能dependency-injected使用纯setter注入。

这个类是传统Java。 它没有依赖的是一个POJO容器特定的接口,基类或注释。


public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;

    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...

}



的ApplicationContext支持constructor-based和setter-based迪豆它管理。

它还支持setter-based DI在一些已经通过构造函数注入依赖项的方法。 您配置的依赖关系的形式BeanDefinition,你使用结合PropertyEditor实例属性从一种格式转换到另一个地方。 然而,大多数Spring用户不直接使用这些类(即。 以编程方式),而是使用XML beandefinitions,注释组件(即。 与@ component类注释,@Controller等等。),或用@Bean方法在基于java的@类。 这些来源的内部转换为实例BeanDefinition和使用Spring的IoC容器加载一个完整的实例。