DI(Dependency Injection)是IOC(Inverse of Control)的具体实现,DI指创建对象不再由控制类自己创建,而是通过容器来自动注入,容器是指通过工厂模式和反射机制构建的工具类,这样做的好处是将创建类的工作交给容器,从而保证了控制类本身的稳定,因为创建类这个工作本身是不稳定的,因为随着用户或内部原因会发生类的变动,容器通过接口来统一类的方法,使得容器足够强大。
IOC是一种思想,是为了减少程序耦合性和OCP(统一开闭原则及即好的代码应该只拓展不修改)而诞生的,想办法统一管理了类的实例化,封装了变化,保证了控制类的稳定
DI是如何实现的
依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入式更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象
如果一个系统有大量的组件,其生命周期和相互之间的依赖关系如果由组件自身来维护,不但大大增加了系统的复杂度,而且会导致组件之间极为紧密的耦合,继而给测试和维护带来了极大的困难。
因此,核心问题是:
- 谁负责创建组件?
- 谁负责根据依赖关系组装组件?
- 销毁时,如何按依赖顺序正确销毁?
解决这一问题的核心方案就是IoC。
传统的应用程序中,控制权在程序本身,程序的控制流程完全由开发者控制,例如:
CartServlet
创建了BookService
,在创建BookService
的过程中,又创建了DataSource
组件。这种模式的缺点是,一个组件如果要使用另一个组件,必须先知道如何正确地创建它。
在IoC模式下,控制权发生了反转,即从应用程序转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,这样,应用程序只需要直接使用已经创建好并且配置好的组件。为了能让组件在IoC容器中被“装配”出来,需要某种“注入”机制,例如,BookService
自己并不会创建DataSource
,而是等待外部通过setDataSource()
方法来注入一个DataSource
:
public class BookService {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}
不直接new
一个DataSource
,而是注入一个DataSource
,这个小小的改动虽然简单,却带来了一系列好处:
BookService
不再关心如何创建DataSource
,因此,不必编写读取数据库配置之类的代码;DataSource
实例被注入到BookService
,同样也可以注入到UserService
,因此,共享一个组件非常简单;- 测试
BookService
更容易,因为注入的是DataSource
,可以使用内存数据库,而不是真实的MySQL配置。
因此,IoC又称为依赖注入(DI:Dependency Injection),它解决了一个最主要的问题:将组件的创建+配置与组件的使用相分离,并且,由IoC容器负责管理组件的生命周期。
近期评论