Spring基础且核心的两大概念——IoC 与 DI



什么是Spring?

        Spring 全称 Spring Framework,它是一个目前市场上最流行、结构最庞大的开源框架,之所以如此,是因为其有独特且全面的应用场景,这样好的生态才使企业一直对青睐。

        注意这句话:Spring 是包含了众多思想、工具、方法的的 IoC 容器

什么是容器?

        这里的容器本质上和我们生活中所说的容器基本是一样的,容器就是用来容纳和取出物品的,那么在编程中具体有 List、Map、Set、Vector、Tomcat(Web容器)、Spring等等,它们也可以存入程序员需要的元素,等用的时候再取出来;这一点在 Spring 中表现的淋漓尽致。


IoC控制反转:

        IoC 全称 Inversion of Control 控制反转,是一种设计思想,也是 Spring 中一个核心概念;

        为了更好的解释控制反转,要先从传统的程序设计思想谈起,以下需要引入一个例子:造一辆车,造一辆车需要设计好车身、车身需要建立在底盘上、底盘的设计又依赖轮子的尺寸,那么这四个因素之间相互制约,下面我们来看看具体怎么设计:

先声明好这几个元素:车(Car类)、车身(framework类)、底座(bottom类)、轮子(Tire类)

        传统程序设计:

// 开始设计车子
public class Car {
    private Framework framework; // 先要有车身这个概念

    public Car() {
        framework = new Framework(); // 开始设计车时new出车身
    }
    // 造车子
    public void init() {
        System.out.println("do car");
        framework.init();
    }
    // 测试入口
    public static void main(String[] args) {
        Car car = new Car();
        car.init();
    }
}
// 车身
public class Framework {
    private Bottom bottom; // 先要有底座这个概念

    public Framework() {
        bottom = new Bottom(); //构造车身时创建轮子
    }
    // 造车身
    public void init() {
        System.out.println("do framework");
        bottom.init();
    }
}
// 底座
public class Bottom {
    private Tire tire;  // 先要有轮子的概念

    public Bottom() {
        tire = new Tire(); // 构造底座时创建轮子
    }
    // 造底座
    public void init() {
        System.out.println("do bottom");
        tire.init();
    }
}
// 轮子
public class Tire {
    private int size = 17; // 设计轮子的尺寸
    // 造轮子
    public void init() {
        System.out.println("do tire -> size = " + size);
    }
}

(重要!!!)

        结合代码可以看到,当我开始设计车子的时候,发现需要先有车身,那么我new一个车身,new车身的时候又发现需要先知道底座,那么就去new一个底座,new底座的时候又发现我还需要知道轮子大小,于是再去new轮子。

        这样用的时候才去创建当然很麻烦,另一方便,这种设计思想导致耦合性极强,我需要的这个类可能又受其他类的约束,放在这个例子当中,一旦我想在构造 Tire 实例时,改一下轮子的尺寸,当然需要传入参数 size,怎么传呢?只能是在 new Car(int size) 这种时候去传,那一旦这样去传,其他几个类的构造方法也需要传参了,我又得去修改其他类的代码,岂不是会产生很多麻烦。

为了降低耦合性,我们 Spring 中的 IoC 就起到了效果:

// 设计车子
public class Car {
    private Framework framework;
    
    // 传入车身对象
    public Car(Framework framework) {
        this.framework = framework;
    }

    public void init() {
        System.out.println("do car");
        framework.init();
    }
}
// 车身
public class Framework {
    private Bottom bottom;

    // 传入底座对象
    public Framework(Bottom bottom) {
        this.bottom = bottom;
    }

    public void init() {
        System.out.println("do framework");
        bottom.init();
    }
}
// 底座
public class Bottom {
    private Tire tire;

    // 传入轮子对象
    public Bottom(Tire tire) {
        this.tire = tire;
    }

    public void init() {
        System.out.println("do bottom");
        tire.init();
    }
}
// 轮子
public class Tire {
    private int size = 17;

    // 随时传入参数
    public Tire(int size) {
        this.size = size;
    }

    public void init() {
        System.out.println("tire --> size = " + size);
    }
}
// 测试用例
public class TestCar {
    public static void main(String[] args) {
        Tire tire = new Tire(20);
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
        car.init();
    }
}

(重要!!!!)

        观察新的代码很容易发现,只是稍微调整了一下每个类的构造方法,之前是我需要时自己new,现在是我需要时别的类给我直接传对象,我自身需要的那个对象直接和传入的对象去做赋值替换即可,如此一来就降低了耦合性,即使轮子的尺寸要改变,也不需要修改其他类的代码了,实质上改变的整个调用链的关系。

        再举一个例子帮助理解:上世纪最初的汽车生产车间中,一个工人可能要负责很多项目的设计、检测、监测,这样就导致工厂招人的难度较高,一个工人要会的多,对于工人可能一会忙这个,一会又要去忙那个,导致生产效率不一定高。后来随着时代发展,工厂改变了思路,实现了流水线生产模式,让一个或多个工人只负责一件事,这样每个环节的工人都各司其职,不受其他环节的影响,便于工厂管理也提高了用人成本和生产效率;

反转体现在哪里?

    上面造车代码中对象的创建顺序:

  • 传统设计过程:Car -> Framework ->Bottom -> Tire;
  • IoC设计过程: Tire -> Bottom -> Framework -> Car;

两种思想导致对象创建和代码执行逻辑刚好发生了反转,这就是反转的亮点!

理解 Spring IoC 的特性:

        上面大篇幅都介绍了 IoC 思想的神奇之处,现在我们把 Spring 和 IoC 结合起来,这才是我们的重点:

        “Spring 是包含了众多思想、工具、方法的IoC容器”

        简言之:Spring 是一个 IoC 容器,所以可以看出 Spring 底层依赖的就是 IoC 思想,同时拥有容器的功能;

  • 将对象存入容器内:相当于把所有要使用的工具都准备好先放到仓库中,包括用完再放回去;
  • 从容器中取出对象:需要什么工具就直接从仓库中和取出来即可;

        为什么这里要强调存和取?因为传统的 new 的过程相当于每次需要的时候才去制作工具,用完了直接就扔了不保存,而在 Spring 中,对象的创建和销毁全都交给 Spring 来管理;


DI依赖注入:

        DI 全称 Dependency Injection,是依赖注入的意思。

        其实 DI 和 IoC 说的是同一件事情,但是用不同的角度去完成,而 IoC 是一种设计思想,DI 是具体实现。

        依赖注入:在 IoC 容器运行期间,动态地将某种依赖关系注入到对象中;

        就像给 maven 项目中配置 pom.xml 文件的过程,也会引入 dependency 依赖,包括给方法传参,类实现接口,这些都是手动注入依赖,而 Spring 的 DI 却可以实现自动、动态的注入依赖。

猜你喜欢

转载自blog.csdn.net/m0_65190367/article/details/130650836