深度理解依赖注入
摘要:提到依赖注入,大家都会想到老马那篇经典的文章。其实,本文就是相当于对那篇文章的解读。所以,如果您对原文已经有了非常深刻的理解,完全不需要再看此文;但是,如果您和笔者一样,以前曾经看过,似乎看懂了,但似乎又没抓到什么要领,不妨看看笔者这个解读,也许对您理解原文有一定帮助。
[1] 依赖在哪里[2] DI的实现方式
[3] Setter Injection
[4] 除了DI,还有Service Locator
2.2 Setter Injection(设值注入)
这种注入方式和构造注入实在很类似,唯一的区别就是前者在构造函数的调用过程中进行注入,而它是通过给属性赋值来进行注入。无怪乎PicoContainer和Spring都是同时支持这两种注入方式。Spring对通过XML进行配置有比较好的支持,也使得Spring中更常使用设值注入的方式:
1<beans>
2 <bean id="MovieLister" class="spring.MovieLister">
3 <property name="finder">
4 <ref local="MovieFinder"/>
5 property>
6 bean>
7 <bean id="MovieFinder" class="spring.ColonMovieFinder">
8 <property name="filename">
9 <value>movies1.txtvalue>
10 property>
11 bean>
12beans>
2 <bean id="MovieLister" class="spring.MovieLister">
3 <property name="finder">
4 <ref local="MovieFinder"/>
5 property>
6 bean>
7 <bean id="MovieFinder" class="spring.ColonMovieFinder">
8 <property name="filename">
9 <value>movies1.txtvalue>
10 property>
11 bean>
12beans>
下面也给出支持设值注入的容器参考实现,大家可以和构造器注入的容器对照起来看,里面的差别很小,主要的差别就在于,在获取对象实例(GetInstance)的时候,前者是通过反射得到待创建类型的构造器信息,然后根据构造器传入参数的类型在容器中进行查找,并构造出合适的实例;而后者是通过反射得到待创建类型的所有属性,然后根据属性的类型在容器中查找相应类型的实例。
设值注入的容器实现伪码
2.3 Interface Injection (接口注入)
这是笔者认为最不够优雅的一种依赖注入方式。要实现接口注入,首先ServiceProvider要给出一个接口定义:
1public interface InjectFinder {
2 void injectFinder(MovieFinder finder);
3}
2 void injectFinder(MovieFinder finder);
3}
接下来,ServiceUser必须实现这个接口:
1class MovieLister: InjectFinder
2{
3 public void injectFinder(MovieFinder finder) {
4 this.finder = finder;
5 }
6}
2{
3 public void injectFinder(MovieFinder finder) {
4 this.finder = finder;
5 }
6}
容器所要做的,就是根据接口定义调用其中的inject方法完成注入过程,这里就不在赘述了,总的原理和上面两种依赖注入模式没有太多区别。