一.依赖简介
一个典型的企业应用程序不是由一个单一的对象组成(或Spring的说法中的bean)。即使是最简单的应用程序也只有几个对象一起工作来呈现最终用户看作是一个连贯的应用程序。如何从定义许多独立的bean定义到完全实现的应用程序,在这些应用程序中对象协作实现目标。
有关spring的设计模式和应用详情可以参考我这篇文章《spring常用设计模式及应用》
二.依赖注入
依赖注入(DI)是一个过程,通过这个过程,对象可以通过构造函数参数,工厂方法的参数或者在构造或返回对象实例后设置的属性来定义它们的依赖关系从工厂方法。然后容器在创建bean时注入这些依赖关系。这个过程从根本上说是相反的,因此名为控制反转(IoC),它本身通过使用类的直接构造或服务定位符模式来控制它自己的依赖关系的实例化或位置。
代码与DI原则相比更加清晰,当对象提供依赖时,解耦更为有效。该对象不查找它的依赖关系,不知道依赖关系的位置或类。因此,您的类变得更容易测试,特别是当依赖关系在接口或抽象基类上时,它们允许在单元测试中使用存根或模拟实现。
DI存在两种主要的变体,基于构造函数的依赖注入和基于Setter的依赖注入
三.基于构造函数的依赖注入
基于构造器的 DI通过容器调用具有多个参数的构造器来完成,每个参数表示一个依赖关系。调用static具有特定参数的工厂方法来构造这个bean几乎是等价的,而且这个讨论同样将参数作为构造函数和static工厂方法来处理。以下示例显示了只能通过构造函数注入进行依赖注入的类。请注意,这个类没有什么特别之处,它是一个POJO,它不依赖于容器特定的接口,基类或注释。
public class SimpleMovieLister { private MovieFinder movieFinder; public SimpleMovieLister(MovieFinder movieFinder) { this.movieFinder = movieFinder; } } |
1.构造器参数匹配
构造函数参数解析匹配使用参数的类型进行。如果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 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> |
同样也可以使用构造器参数名称匹配
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg name="years" value="7500000"/> <constructor-arg name="ultimateAnswer" value="42"/> </bean> |
2.基于Setter方法
在调用无参数构造函数或无参数静态工厂方法实例化bean时,基于bean的调用Setter方法是通过bean调用Setter方法完成的。
public class SimpleMovieLister { private MovieFinder movieFinder; public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } } |
Spring团队通常提倡构造函数注入,因为它使一个能够将应用程序组件作为不可变对象实现,并确保所需的依赖项不是null。此外,构造函数注入的组件总是返回到完全初始化状态的客户机(调用)代码中。作为一个方面说明,大量的构造函数的参数是一个糟糕的代码的气味,这意味着类可能有太多的责任和应该被更好的问题解决的适当分离。
Setter注入应该主要用于可选的依赖关系,这些依赖关系可以在类中分配合理的默认值。否则,非空检查必须在代码使用依赖项的任何地方执行。第=一个优势就是在于setter方法使该类的对象能够重新配置或重新注入。因此通过JMX MBean管理是setter注入一个引人注目的用例.