likes
comments
collection
share

Spring是什么?IoC是什么?DI又是什么?

作者站长头像
站长
· 阅读数 13

Spring是什么?

  Spring指的是Spring Framework(Spring框架)是包含了众多工具方法的IoC容器。

1.什么是容器?

  Spring是包含了众多工具方法的IoC容器。那么这里的容器是什么意思?很好理解,容器就是要能装东西、取东西,就好比如水杯、背包、还有数据结构中的Map、List等。那么Spring也是可以装东西、取东西,不过这里的这个“东西”就是java中的对象。(后文介绍)

  没错,Spring就是装对象的容器。(至于怎么存取对象,这里先不作讨论,本篇先注重其概念,详细的后面会更新。)

2.什么是IoC?

  IoC容器中的IoC是什么呢?IoC的全称是Inversion of Control,意思是“控制反转”,“控制反转”又是什么?我们通过下面的案例来慢慢体会“控制反转”是什么?

2.1 传统编程方式

  案例:制造自行车。

Spring是什么?IoC是什么?DI又是什么?

  要想造出一辆自行车必须要依赖轮子才能跑,轮子需要链条来转动,而链条需要脚踏板来牵引。

//自行车
public class Back {
    public void init(){
        //依赖轮胎
        Wheel weel = new Wheel();
        weel.init();
    }
}

//轮胎
class Wheel{
    public void init(){
        //依赖链条
        Chain chain = new Chain();
        chain.init();
    }
}

//链条
class Chain{

    public void init(){
        //依赖脚踏板
        Pedal pedal = new Pedal();
        pedal.init();
    }
}

//脚踏板
class Pedal{
    private String shape = "正方形";
    
    public void init(){
        System.out.println("脚踏板的形状:" + shape);
    }
}
public class Main{
    public static void main(String[] args) {
        Back back = new Back();
        back.init();
    }
}


输出:脚踏板的形状:正方形

  那如果现在我有新的需求了呢?比如我想要一个三角形的脚踏板,上面的代码该如何修改呢?其实可以在Pedal类里面加个构造方法:

//脚踏板
class Pedal{
    private String shape;

	//方便修改类型
    public Pedal(String shape){
        this.shape = shape;
    }

    public void init(){
        System.out.println("脚踏板的形状:" + shape);
    }
}

  我们虽然加了一个构造方法,但是这构造方法里的shape变量谁传进来呢?是上面的Chain传进来的,但是Chain里面没有shape呀,那么也是需要上一级的类传进来,最后的代码就是:


//自行车
public class Back {
    
    private Wheel wheel;
    
    //传进来什么就new什么
    public Back(String shape){
        wheel = new Wheel(shape);
    }
    
    public void init(){
        //依赖轮胎
        weel.init();
    }
}

//轮胎
class Wheel{
    private Chain chain;
    
    //传进来什么就new什么
    public Wheel(String shape){
        chain = new Chain(shape);
    }
    
    public void init(){
        chain.init();
    }
}

//链条
class Chain{

    private Pedal pedal;

    //传进来什么就new什么
    public Chain(String shape){
        pedal = new Pedal(shape);
    }
    
    public void init(){
        //依赖脚踏板
        pedal.init();
    }
}

//脚踏板
class Pedal{
    private String shape;
    
    public Pedal(String shape){
        this.shape = shape;
    }

    public void init(){
        System.out.println("脚踏板的形状:" + shape);
    }
}

//测试类
class Main{
    public static void main(String[] args) {
        //传入我们得需求:“三角形”
        Back back = new Back("三角形");
        back.init();
    }
}

结果:脚踏板的形状:三角形

  从上面的代码可以看出,当最底层的代码改动后,整个调用链上的所有的代码都是要修改的,耦合性很高。

  是什么原因导致的上面的问题呢?问题出现在每个类⾃⼰创建了下级类,这就会出现当下级类发⽣改变时,⾃⼰也要跟着修改。

2.2 控制反转的方式

  问题已经找到了,那么解决方法就出来了:我们将原来自己创建下级类的方式改为传递的方式:

//自行车
public class Back {

    private Wheel wheel;

    //需要外面传入一个轮胎,而不是我自己造了
    public Back(Wheel wheel){
        this.wheel = wheel;
    }

    public void init(){
        //依赖轮胎
        wheel.init();
    }
}

//轮胎
class Wheel{
    private Chain chain;

    //需要外面传入一个链条,而不是我自己造了
    public Wheel(Chain chain){
        this.chain = chain;
    }

    public void init(){
        chain.init();
    }
}

//链条
class Chain{

    private Pedal pedal;

    //需要外面传入一个脚踏板,而不是我自己造了
    public Chain(Pedal pedal){
        this.pedal = pedal;
    }

    public void init(){
        //依赖脚踏板
        pedal.init();
    }
}

//脚踏板
class Pedal{
    private String shape;

    public Pedal(String shape){
        this.shape = shape;
    }

    public void init(){
        System.out.println("脚踏板的边长:" + shape);
    }
}

//测试类
class Main{
    public static void main(String[] args) {
    
        Pedal pedal = new Pedal("长方形");//外面造一个脚踏板
        Chain chain = new Chain(pedal);//传入,造个链条
        Wheel wheel = new Wheel(chain);//传入,造个轮胎
        Back back = new Back(wheel);//传入,造自行车
        back.init();
    }
}

结果:脚踏板的边长:长方形

  上面的方式,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的, 这样就解耦了。

Spring是什么?IoC是什么?DI又是什么?

2.3 再来理解IoC

  我们用上面的案例来理解,我们来对比两种方式的类的创建顺序:

Spring是什么?IoC是什么?DI又是什么?

  第一种方式是先创建Back类然后依次往下创建,前一个类依赖于后一个类,后一个类修改后,前一个类也必须修改;上级类控制下级类,因为在上级类中是通过new的方式创建下级类的。

  第二种方式是从后往前的创建,但是这里的是下级对象注⼊到当前对象中,在当前类中我不操心怎么new的对象,我只管用就行了,上级类不再控制下级类了,当前类都是不受影响的,这就是典型的控制反转(IoC) 的实现思想。

2.4 什么是 Spring IoC 容器?

  上文提到:Spring 是包含了多个⼯具⽅法的IoC 容器,那怎么理解 Spring 是 IoC容器呢?

  既然是容器,那么Spring将对象存⼊到容器、并且能从容器中取出对象。怎么理解这句话?就是将对象存储在容器中,以后需要的时候直接取就⾏了,⽤完再把它放回到仓库,而不用自己去new一个对象了,不用管new的细节了。

  这与IoC有什么联系呢?在这之前我们先得先了解 DI(Dependency Injection)是什么?

2.4 什么是 DI ?

  DI的英文是(Dependency Injection),意思是依赖注入。提到“注入”有没有想到什么?我们上文的案例中第二种方式提到过,怎么造一个自行车?就是下级类通过注入的方式,将下级类传入到上级类。这中间有一个要注意的点,那就是中间没有new的环节!我是直接传进来的,以Main类之外的视角来看,我是不需要操心怎么去new的,我只负责接受就行了。

  那么这里的DI就是这个作用,DI就相当于把容器中的类取出来让我们用的这个过程,我们不需要操心怎么去new的,在Spring中是通过注解的方式来实现这个过程。下面是简单的示意图(详细的介绍待更新)。

//轮胎
@Controller
class Wheel{
    
    @Autowired//这里就是将容器中的 Chain 对象注入进来(直接复值),不用我们自己 new 一个。
    private Chain chain;
    
    public void init(){
        chain.init();
    }
}

//链条
@Controller
class Chain{

    @Autowired//这里就是将容器中的 Pedal 对象注入进来(直接复值),不用我们自己 new 一个。
    private Pedal pedal;
    
    public void init(){
        pedal.init();
    }
}

  这就是DI(Dependency Injection)依赖注入的意思,回到上面的问题:这与IoC有什么联系呢?Spring通过DI(依赖注入)的方式可以实现控制反转来解耦合,有了控制反转不就是IoC了吗?, Spring注解等方式来实现依赖注入从而进行控制反转,并且它是一个装对象的容器。所以Spring是一个IoC容器。

ID(依赖注入)IoC(控制反转)的一种实现方式,IoC 是“⽬标”也是⼀种思想或者是设计模式,⽽DI就属于具体的实现。

  下面我们看看CatGPT是如何“理解”IoC以及DI的:

Spring是什么?IoC是什么?DI又是什么?

Spring是什么?IoC是什么?DI又是什么?

Spring是什么?IoC是什么?DI又是什么?

(ps:如有错误请在评论区指出,谢谢~)