下面的例子显示了相应的Java类:
public class DefaultServiceLocator { private static ClientService clientService = new ClientServiceImpl(); private static AccountService accountService = new AccountServiceImpl(); public ClientService createClientServiceInstance() { return clientService; } public AccountService createAccountServiceInstance() { return accountService; } }这种方法表明,可以通过依赖注入(dependency injection)对工厂bean本身进行管理和配置。请参阅详细的依赖关系和配置。
在Spring文档中,"factory bean"指的是在Spring容器中配置并通过实例或静态工厂方法创建对象的bean。相比之下,FactoryBean(注意大写)指特定于spring的FactoryBean。
Dependencies一个典型的企业应用程序不包含单个对象(或Spring术语中的bean)。即使是最简单的应用程序,也有一些对象一起工作,以显示最终用户所看到的一致的应用程序。
下一节将解释如何从定义独立的许多bean定义过渡到一个完全实现的应用程序,在这个应用程序中,对象协作以实现目标。
依赖注入(Dependency injection)是一个过程,在这个过程中,对象只通过构造函数参数、工厂方法的参数或从工厂方法构造或返回的对象实例上设置的属性来定义它们的依赖关系(也就是说,它们工作的其他对象)。然后容器在创建bean时注入这些依赖项。这个过程本质上是bean本身的翻转(因此称为控制翻转),它通过使用类或服务定位器模式的直接构造来控制其依赖项的实例化或位置。
使用DI原则,代码更简洁,当对象具有依赖关系时,解耦更有效。对象不查找依赖项,也不知道依赖项的位置或类。因此,您的类变得更容易测试,特别是当依赖关系是在接口或抽象基类上时,这允许存根或模拟实现在单元测试中使用。
DI存在于两种主要变体中:基于构造函数的依赖项注入和基于Setter的依赖项注入。
Constructor-based Dependency Injection基于构造函数的DI由容器调用构造函数来完成,该构造函数有许多参数,每个参数都表示依赖关系。调用带有特定参数的静态工厂方法来构造bean几乎是等价的,本文将把参数类似地处理给构造函数和静态工厂方法。下面的例子展示了一个只能通过构造函数注入依赖注入的类:
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... }注意,这个类没有什么特别之处。它是一个POJO,不依赖于容器特定的接口、基类或注释。
Constructor Argument Resolution构造函数参数解析匹配通过使用参数的类型来实现。如果bean定义的构造函数参数中不存在潜在的歧义,那么在bean定义中定义构造函数参数的顺序就是在实例化bean时将这些参数提供给适当的构造函数的顺序。考虑以下类:
package x.y; public class ThingOne { public ThingOne(ThingTwo thingTwo, ThingThree thingThree) { // ... } }假设ThingTwo和ThingThree类不通过继承关联,则不存在潜在的歧义。因此,下面的配置可以很好地工作,您不需要在元素<constructor-arg/>中显式指定构造函数参数索引或类型。
<beans> <bean> <constructor-arg ref="thingTwo"/> <constructor-arg ref="thingThree"/> </bean> <bean/> <bean/> </beans>当引用另一个bean时,类型是已知的,并且可以进行匹配(就像前面的例子那样)。当使用简单类型(如)时,Spring无法确定值的类型,因此在没有帮助的情况下无法按类型匹配。考虑以下类:
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; } }Constructor argument type matching
在前面的场景中,如果使用type属性显式地指定构造函数参数的类型,容器可以使用与简单类型匹配的类型。如下例所示:
<bean> <constructor-arg type="int" value="7500000"/> <constructor-arg type="java.lang.String" value="42"/> </bean>Constructor argument index
可以使用index属性显式地指定构造函数参数的索引,如下例所示:
<bean> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/> </bean>除了解决多个简单值的模糊性之外,指定索引还可以解决构造函数具有相同类型的两个参数的模糊性问题。
基于0的指数
Constructor argument name
您还可以使用构造函数参数名来消除值歧义,如下例所示:
<bean> <constructor-arg value="7500000"/> <constructor-arg value="42"/> </bean>