SPRING:控制反转IoC和 依赖注入DI

SPRING:控制反转IoC和 依赖注入DI

  • 控制反转IoC(Inversion of Control)和 依赖注入DI(Dependency Injection)

 

IoC和DI

  面向对象六大原则之依赖倒置原则(Dependence Inversion Principle,DIP):程序要依赖于抽象接口,不要依赖于具体实现。

  控制反转(IoC)则是DIP的一种设计体现。

  而依赖注入(DI)则是实现控制反转的一种方法。

 

  一个场景:程序员去买一台惠普电脑:

  SPRING:控制反转IoC和 依赖注入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);

 

  

上一篇:Spring源码学习分享系列篇(四) 解析文件路径


下一篇:spring bean源码