15.2 依赖注入
在过去数年间,依赖注入技术作为代码可测试性的一个解决方案已经被广泛应用。实际上,Spring、谷歌Guice等伟大框架都采用了依赖注入技术。那么,什么是依赖注入技术?
什么是依赖注入
很多人在使用中并不区分依赖注入和控制反转(IoC),尽管Martin Fowler在其文章中已分析了二者的不同。
http://martinfowler.com/articles/injection.html
实例
简单来说,依赖注入的情况如下。
有两个组件A和B,A依赖于B。假定A是一个类,且A有一个方法importantMethod使用到了B,如下:
1 | public class A { |
要使用B类,A类必须先获得组件B的实例的引用。若B是一个具体类,则可通过new关键字直接创建组件B实例。但是,如果B是接口,且有多个实现,则问题就变得复杂了。我们固然可以任意选择接口B的一个实现类,但这也意味着A的可重用性大大降低了,因为无法采用B的其他实现。
依赖注入是这样处理此类情景的:接管对象的创建工作,并将该对象的引用注入需要该对象的组件。
以上述例子为例,依赖注入框架会分别创建对象A和对象B,将对象B注入到对象A中。
依赖注入方式
为了能让框架进行依赖注入,程序员需要编写特定的set方法或者构造方法。
setter方法注入
例如,为了能将B注入到A中,类A会被修改成如下形式:
1 | public class A { |
修改后的类A新增了一个setter方法,该setter方法将会被框架调用,用以注入一个B的实例。由于对象依赖由依赖注入,类A的importantMethod方法不再需要在调用B的usefulMethod方法前去创建一个B的实例。
构造器注入
当然,也可以采用构造器方式注入,如下所示:
1 | public class A { |
本例中,Spring会先创建B的实例,再创建实例A,然后把B注入到实例A中。
注意Spring管理的对象称为beans。
通过提供一个控制反转容器(或者依赖注入容器),Spring为我们提供一种可以“聪明”地管理Java对象依赖关系的方法。其优雅之处在于,程序员无须了解Spring框架的存在,更不需要引入任何Spring类型。
版本支持
- 从1.0版本开始,
Spring就同时支持setter和构造器方式的依赖注入。 - 从2.5版本开始,通过
Autowired注解,Spring支持基于field方式的依赖注入,但缺点是程序必须引入org.springframework.beans.factory.annotation.Autowired,这对Spring产生了依赖,这样,程序无法直接迁移到另一个依赖注入容器内。
使用Spring,程序几乎将所有重要对象的创建工作移交给Spring,并配置如何注入依赖。
Spring支持XML和注解两种配置方式。此外,还需要创建一个ApplicationContext对象,ApplicationContext对象代表一个Spring控制反转容器,
ApplicationContext接口
org.springframework.context.ApplicationContext接口有多个实现,包括ClassPathXmlApplicationContext和FileSystemXmlApplicationContext。这两个实现都需要至少一个包含beans信息的XML文件。ClassPathXmlApplicationContext尝试在类加载路径中加载配置文件,而FileSystemXmlApplicationContext则从文件系统中加载。
下面为从类路径中加载config1.xml和config2.xml的ApplicationContext创建的一个代码示例:
1 | ApplicationContext context = |
可以通过调用ApplicationContext的getBean方法获得对象:
1 | Product product = context.getBean("product", Product.class); |
getBean方法会查询id为product且类型为Product的bean对象。
注
理想情况下,我们仅需在测试代码中创建一个ApplicationContext,应用程序本身无须处理。对于Spring MVC应用,可以通过一个Spring Servlet来处理ApplicationContext,而无须直接处理。
原文链接: 15.2 依赖注入