一,为什么会出现依赖注入这个概念?
控制反转(IoC=Inversion of Control),是一种思想,指的是控制权的转移,即(依赖)控制权由应用代码中转到了第三方外部容器(如Spring容器)。
二,Spring-IoC容器
对于 Spring 框架来说,所谓 IoC就是由 Spring 来负责控制对象的生命周期和对象间的关系, 用 XML 来定义生成对象的模式。
在一个对象中,如果要使用另外的对象,就必须得到它(自己 new 一个,或者从 JNDI 中查询一个),使用完之后还要将对象销毁(比如 Connection 等)。那么 Spring-IoC 是如何做的呢?
所有的类都会在 Spring 容器中登记,告诉 Spring 你是个什 么东西,你需要什么东西,然后 Spring 会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 Spring 。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制。
二,Spring-IoC的使用
在下面例子中,我们使用 Spring 提供的 IoC 容器来管理我们的用户注册类。
UserRegister
依赖于UserDao
的实现类,我们使用 IoC 容器在运行期动态的为UserRegister
注入UserDao
的实现类。即UserRegister
对UserDao
的依赖关系由容器注入,UserRegister
不用关心UserDao
的任何具体实现类。如果要更改用户的持久化方式,只要修改配置文件 applicationContext.xml 即可。依赖注入机制减轻了组件之间的依赖关系,同时也大大提高了组件的可移植性,这意味着,组件得到重用的机会将会更多。
用户注册类UserRegister
的部分代码如下:
public class UserRegister { private UserDao userDao = null;//由容器注入的实例对象 public void setUserDao(UserDao userDao){ this.userDao = userDao; } // UserRegister的业务方法 }
在其它的UserRegister
方法中就可以直接使用userDao
对象了,它的实例由Spring
容器主动为它创建。但是,如何组装一个UserDao
的实现类到UserRegister
中呢?哦,Spring 提供了配置文件来组装我们的组件。Spring 的配置文件 applicationContext.xml 代码片断如下:
<bean id="userRegister" class="com.dev.spring.simple.UserRegister"> <property name="userDao"><ref local="userDao"/></property> </bean> <bean id="userDao" class="com.dev.spring.simple.MemoryUserDao"/>
四,依赖注入
组件的依赖关系由容器实现,那么容器如何知道一个组件依赖哪些其它的组件呢?如上面例子中,容器如何得知UserRegister
依赖于UserDao
呢?
Spring的组件提供了一系列所谓的回调方法(也叫注入方法),这些注入方法会告知容器它所依赖的组件,也就是将实例变量传到另一个对象中去。依赖注入为实现IOC思想做技术支持。
根据注入方法的不同,我们可以将 IoC 分为三种形式:接口注入,值注入,构造方法注入。根据注入类型的不同,分为:值类型注入(8大基本数据类型),引用类型注入(Dao注入Service,service注入action,也就是依赖对象注入)。
五,依赖注入与控制反转
- 控制反转是一种思想
- 依赖注入是一种设计模式
IoC框架使用依赖注入作为实现控制反转的方式,但是控制反转还有其他的实现方式,所以不能将控制反转和依赖注入等同。
六,总结
- 控制反转是一种在软件工程中解耦合的思想,调用类只依赖接口,而不依赖具体的实现类,减少了耦合。控制权交给了容器,在运行的时候才由容器决定将具体的实现动态的“注入”到调用类的对象中。
- 依赖注入是一种设计模式,可以作为控制反转的一种实现方式。依赖注入就是将实例变量传入到一个对象中去(Dependency injection means giving an object its instance variables)。
- 通过IoC框架,类A依赖类B的强耦合关系可以在运行时通过容器建立,也就是说把创建B实例的工作移交给容器,类A只管使用就可以。