SPRING:控制反转IoC和 依赖注入DI
- 控制反转IoC(Inversion of Control)和 依赖注入DI(Dependency Injection)
IoC和DI
面向对象六大原则之依赖倒置原则(Dependence Inversion Principle,DIP):程序要依赖于抽象接口,不要依赖于具体实现。
控制反转(IoC)则是DIP的一种设计体现。
而依赖注入(DI)则是实现控制反转的一种方法。
一个场景:程序员去买一台惠普电脑:
不符合DIP的程序设计:
//惠普电脑类 public class HpComputer { private String name; HpComputer(){ name="惠普电脑"; } public String getName() { return name; } } //程序员类 public class Programmer { private HpComputer hpComputer; Programmer(){ hpComputer=new HpComputer(); } public void buy(){ System.out.println(hpComputer.getName()); } } //业务 public class Main { public static void main(String[] args) { Programmer programmer=new Programmer(); programmer.buy(); } }
代码中 Programmer 类的实例化需要调用 HpComputer 类的构造函数,Programmer类对HpComputer类产生了一种依赖关系,这种关系即软件工程中提到的耦合。
若电脑初始时需要指定购买电脑的具体型号,此时HpComputer的构造函数变为:
HpComputer(String name){ this.name=name; }
此时,程序员的构造器也需要做相应调整:
public Programmer(){ hpComputer=new HpComputer("暗夜精灵8"); }
在一个大的项目中,一个类被使用的地方可能远不止一次,项目建设过程中可能经常涉及变动,若类与类之间一直存在这种高耦合的依赖关系,维护的代价是很大的。
Programmer类想使用HpComputer类,可以想到,除了直接new出一个实列,还可以通过入参的形式将HpComputer类传入Programmer类。我的理解,这种把所依赖的类以参数的方式传入的方案,就是依赖注入。
依赖注入有三种方式,私以为,三种方法的本质都是参数传递:
1、构造函数传入:
//程序员 public class Programmer { private HpComputer hpComputer; public Programmer(HpComputer hpComputer){ this.hpComputer=hpComputer; } public void buy(){ System.out.println(hpComputer.getName()); } } //业务 public class Main002 { public static void main(String[] args) { HpComputer hpComputer=new HpComputer("暗夜精灵8"); Programmer programmer=new Programmer(hpComputer); programmer.buy(); } }
2、setter传递:
//程序员 public class Programmer { private HpComputer hpComputer; public void setHpComputer(HpComputer hpComputer) { this.hpComputer = hpComputer; } public void buy(){ System.out.println(hpComputer.getName()); } } //业务 public class Main002 { public static void main(String[] args) { HpComputer hpComputer=new HpComputer("暗夜精灵8"); Programmer programmer=new Programmer(); programmer.setHpComputer(hpComputer); programmer.buy(); } }
3、接口传递:
//电脑类 public interface HpComputer { String getName(); } class AnYingJingLing8 implements HpComputer{ private String name; AnYingJingLing8(String name){ this.name=name; } @Override public String getName() { return name; } } //程序员类 public class Programmer { private HpComputer hpComputer; public void setHpComputer(HpComputer hpComputer) { this.hpComputer = hpComputer; } public void buy(){ System.out.println(hpComputer.getName()); } } //业务类 public class Main002 { public static void main(String[] args) { HpComputer hpComputer=new AnYingJingLing8("暗夜精灵8"); Programmer programmer=new Programmer(); programmer.setHpComputer(hpComputer); programmer.buy(); } }
以上是我对DI的理解,现在谈谈 Spring的IoC 和 IoC容器 :
我的理解中,IoC是一种设计思路:传统Java SE程序设计,对象的实列是由程序控制的(如直接new),而spring中对象是由IoC容器控制的,由IoC容器管理对象的生命周期,在合适的时候注入。spring程序启动时,会对一个个的bean(可以通过xml配置或注解的形式配置bean)进行初始化,上述场景中,可以把这段代码看作IoC容器对bean初始化时执行的操作:
HpComputer hpComputer=new AnYingJingLing8("暗夜精灵8"); Programmer programmer=new Programmer(); programmer.setHpComputer(hpComputer);