控制反转(Inversion of Control,缩写为IoC),是面向对象变成中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式是依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。(百度百科)
这里我们需要注意,IOC != DI,IOC是一个原则,DI只是实现IOC的一种手段。
那么我们该如何理解控制反转这个词呢?
让我们回想一些实际应用的场景,我们现在有两个类A和B,当我们需要在A中调用B类的某个方法时,我们要怎么做?
public class Guo{
public void cook(Jiaobanji j){
j.fix();
System.out.println("料理");
}
}
public class Jiaobanji{
public void fix(){
System.out.println("搅碎");
}
}
如上例,假设我们此时需要包饺子,需要将肉打成肉馅之后用锅进行简单的烹饪,那我们首先就需要用搅拌机将食材打碎,然后再放进锅里面进行料理,此时我们可以看到,“料理”这一步是依赖于搅拌机所搅拌出来的馅的,那如果我们用代码实现调用的时候需要怎么写呢?
public static void main(String args[]){
Guo g = new Guo();
g.cook(new Jiaobanji());
}
我们用最普通的方法来书写,通过上述代码是可以实现我们的预期功能的
但是我们来思考一个问题,有一天搅拌机坏了!我们不得不使用传统的菜刀来切碎食材,那么这个时候我们怎么办的?对于上述代码,我们只能去修改cook()方法之中的参数,将搅拌机来更改为一个菜刀类,通过菜刀的方法来处理食材。那我们可能有很多种烹饪方式都需要搅拌机或菜刀来处理食材,那总不能我们每次想更换一次工具,或者换一台新的搅拌机就需要把所以普烹饪方法里面的处理食材的步骤全部修改一遍吧?这过于繁琐也太不安全了,如果我们某个地方没有修改正确都可能会带来程序的错误和崩溃,这显然是我们无法接受的。
那我们该如何解决这种问题呢?让我们来看下面这一种代码
public class Guo{
private ProcessFood p;
public void setProcessFood(ProcessFood p){
this.p = p;
}
public void cook()
p.cut();
System.out.println("料理");
}
}
public interface ProcessFood{
public void cut();
}
public class Jiaobanji implements ProcessFood{
public void cut(){
System.out.println("搅碎");
}
}
public class Caidao implements ProcessFood{
public void cut(){
System.out.println("切碎");
}
}
让我们来看一下上述代码,继续刚才的场景,本来我们使用的是搅拌机,现在搅拌机坏了,那么在上述代码中,我们只需要把锅中的食材加工的施行者由搅拌机换为菜刀就可以了。那么这个步骤如果由锅来自己完成,即代码中写为private ProcessFood p = new Jiaobanji();
这种静态形式的话就又要我们去代码中一个一个修改了,但是如果像我们上述代码这样,由set方法来外部给锅注入加工者,不由锅自己来new一个加工者对象的话,我们就可以通过外部配置来统一修改所有需要加工者的类中的依赖了!
上述转变总结一下即为由锅来主动new加工者,变为了由外部的某个东西来给锅注入锅需要的加工者对象,由主动行为变为了被动行为,将控制加工者实例化的权责交给了外部,这就是控制反转的含义,而这个外部的容器,在spring之中就是spring IOC容器。
上述过程实际应为DI(依赖注入)的过程,是为了让大家更好的理解IOC原则,只是IOC原则的其中一种实现形式
Spring IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 IOC 容器负责创建对象,将对象连接在一起,配置这些对象,并从创建中处理这些对象的整个生命周期,直到它们被完全销毁。
而对于Spring IOC容器的技术剖析与使用规则,有时间会另写博文,敬请期待