为什么要 IOC?
- 开饭店的例子
如果我要开一家饭店,需要一个川菜厨师,男服务员,桌子。
public class Restraunt {
private SichuanCook cook;
private MaleWaiter waiter;
private List<Table> tables
}
但不久我们发现,川菜在当地并不受欢迎,我要改成粤菜餐厅。
于是我们把川菜厨师辞了,改请粤菜厨师。
public class Restraunt {
private GuangdongCook cook;
private MaleWaiter waiter;
private List<Table> tables
}
----但不就我们发现,粤菜也不能完全满足当地需求,我们需要一个能同时做粤菜和东北菜的全能厨师 AllRoundCook。
----更不幸的是,我们的男服务员因为态度问题屡次被投诉,必须撤换重新招聘态度好的女服务员 FemaleWaiter。
这一切,都需要我们亲自去完成,从辞退到招聘。
- 中介机构 IOC
这时,我们就想到了中介机构。中介机构能为我做什么呢?
----按照我的指示,替我完成厨师和服务员的招聘,解雇。
我需要做什么呢?
----给中介机构一张单子,告诉它我需要什么样的厨师和服务员。
是不是顿时减轻了负担?
- 依赖反转
IOC: Inversion of Control, 即控制反转。
在程序语言中:
招聘 = 类初始化 + 构造对象
解聘 = 对象析构
- 依赖注入
那么饭店怎么选择员工呢?
在程序语言中,即依赖注入,有三种方式:
1. 构造函数注入
public class Restraunt {
private Cook cook;
public Restraunt(Cook cook) {
this.cook = cook;
}
}
public interface Cook {
void cook();
}
public class SichuanCook implements Cook {
public void cook() {}
}
public class GuangdongCook implements Cook {
public void cook() {}
}
在 spring 的配置文件中注册 Restraunt,将 SichuanCook 通过 constructor-arg 标签注入到 Restraunt 的构造方法。
<bean id="restraunt" class="Restraunt">
<constructor-arg ref="cook"></constructor-arg>
</bean>
<bean id="cook" class="SichuanCook"></bean>
2. Setter 注入
public class Restraunt {
private Cook cook;
public void setCook(Cook cook) {
this.cook = cook;
}
}
在 spring 配置中注册 Restraunt,将 SichuanCook 通过 property 标签注入到 Restraunt。
<bean id="restraunt" class="Restraunt">
<property name="cook" ref="sichuanCook"></property>
</bean>
<bean id="sichuanCook" class="SichuanCook"></bean>
3. 注解注入
public class Restraunt {
@Resource
private Cook cook;
}
public interface Cook {
void cook();
}
@Service
public class SichuanCook implements Cook {
public void cook() {}
}
public class GuangdongCook implements Cook {
public void cook() {}
}
- IOC 的好处
1. 减少代码耦合
不再需要通过代码来写死 Cook 的具体类型。Restraunt 和具体的 Cook 实现类已经完全脱离开来,只要 Cook 实现类遵守和 Restraunt 定的协定(implement Cook),就都可与 Restraunt 无缝对接。
2. 方便单元测试
如果 A, B 两人分别实现 SichuanCook 和 Restraunt 类,Restraunt 类先实现后,可以通过 MockCook 先开始测试 Restraunt 的代码。
3. 灵活性好,方便扩展,可维护性更好
通过配置文件,可以做到改变实现类,而不改变任何一个调用者的代码。
IOC 实现原理
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。
从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。(来自:https://www.cnblogs.com/superjt/p/4311577.html)
其他参考文档:
https://www.cnblogs.com/esileme/p/7479879.html IOC底层实现原理
https://www.cnblogs.com/superjt/p/4311577.html
https://www.jianshu.com/p/ad05cfe7868e
https://www.jianshu.com/p/17b66e6390fd
https://www.cnblogs.com/yoci/p/10642553.html
https://www.jianshu.com/p/4b31dacf3a63 Spring IOC 原理