Spring IoC & DI 介绍

目录

1.什么是IoC?

 1) IoC介绍

(1).传统程序开发

问题分析

解决方案

IoC程序开发

IoC的优势

DI介绍


1.什么是IoC?

IoC是Spring的核心思想,也是常见的面试题,那么什么是IoC呢?

其实IoC前面已经使用过了,我们在前面讲到,在类上面添加 @RestController 和 @Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交给Spring管理,就是IoC思想.

IoC: Inversion of Controller(控制反转),也就是说Spring是一个"控制反转"的容器.

什么是控制反转呢? 也就是控制权反转.什么的控制权发生了反转呢?获得依赖对象的过程被反转了,也就是说,当需要某个对象时,传统开发模式中需要自己通过new创建对象,现在不需要再进行创建,把创建对象的任务交给容器,程序中只需要依赖注入(Dependency Injection,DI)就可以了.

这个容器称为: IoC容器.Spring是一个IoC容器,所以有时候Spring 也称为Spring容器.

 1) IoC介绍

接下来我们通过案例来了解一下什么是IoC

需求: 造一辆车

(1).传统程序开发

我们实现的思路是这样的: 

先设计轮子(Tire),然后根据轮子的大小设计地盘(Bottom),接着根据地盘设计车身(Framework),最后根据车身设计好整个汽车(Car).这里就出现了一个"依赖关系" : 汽车依赖车身,车身依赖地盘,地盘依赖轮子.

最终程序的实现代码如下: 

public class NewCarExaple {
    public static void main(String[] args) {
        Car car = new Car();
        car.run();
    }
    /*
    * 汽车对象
    * */
    static class Car {
        private Framework frameWork;
        public Car() {
            frameWork = new Framework();
            System.out.println("Car init...");
        }
        public void run() {
            System.out.println("Car run...");
        }
    }
    /*
    * 车身类
    * */
    static class Framework {
        private Bottom bottom;
        public Framework() {
            bottom = new Bottom();
            System.out.println("Framework init...");
        }
    }
    /*
    * 底盘类
    * */
    static class Bottom {
        private Tire tire;

        public Bottom() {
            this.tire = new Tire();
            System.out.println("Bottom init...");
        }
    }
    /*
    * 轮胎类
    * */
    static class Tire {
        private int size;
        public Tire() {
            this.size = 17;
            System.out.println("轮胎尺寸: " + size);
        }
    }
}

问题分析

这样设计看起来没有问题,但是可维护性却很低

接下来需求有了变更: 随着对车的需求量越来越大,个性化需求也会越来越多,我们需要加工多种尺寸的轮胎.

那这个时候就要对上面的程序进行修改了,修改后的代码如下所示: 

public class NewCarExaple {
    public static void main(String[] args) {
        Car car = new Car(20);
        car.run();
    }
    /*
    * 汽车对象
    * */
    static class Car {
        private Framework frameWork;
        public Car(int size) {
            frameWork = new Framework(size);
            System.out.println("Car init...");
        }
        public void run() {
            System.out.println("Car run...");
        }
    }
    /*
    * 车身类
    * */
    static class Framework {
        private Bottom bottom;
        public Framework(int size) {
            bottom = new Bottom(size);
            System.out.println("Framework init...");
        }
    }
    /*
    * 底盘类
    * */
    static class Bottom {
        private Tire tire;

        public Bottom(int size) {
            this.tire = new Tire(size);
            System.out.println("Bottom init...");
        }
    }
    /*
    * 轮胎类
    * */
    static class Tire {
        private int size;
        public Tire(int size) {
            this.size = 17;
            System.out.println("轮胎尺寸: " + size);
        }
    }
}

从上面的代码可以看出, 以上程序的问题: 当最底层代码改动之后,整个调用链上的所有代码都需要修改.

程序的耦合度非常高.

解决方案

在上面程序中,我们是根据轮子的尺寸设计的地盘,轮子的尺寸一改,底盘的设计就得修改.同样因为我们是根据地盘设计的车身,那么车身也得修改,同理汽车设计也得改,也就是整个设计几乎都得修改

我们尝试换一种思路,我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计地盘,最后根据地盘来设计轮子,这时候,依赖关系就倒置了: 轮子依赖地盘,地盘依赖车身,车身依赖汽车.

IoC程序开发

基于以上思路,我们把调用汽车的程序示例改造一下,把创建子类的方式,改为注入的方式,具体代码如下:

public class IocCarExample {
    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.run();
    }
    /*
     * 汽车对象
     * */
    static class Car {
        private Framework frameWork;
        public Car(Framework framework) {
            this.frameWork = framework;
            System.out.println("Car init...");
        }
        public void run() {
            System.out.println("Car run...");
        }
    }
    /*
     * 车身类
     * */
    static class Framework {
        private Bottom bottom;
        public Framework(Bottom bottom) {
            this.bottom = bottom;
            System.out.println("Framework init...");
        }
    }
    /*
     * 底盘类
     * */
    static class Bottom {
        private Tire tire;

        public Bottom(Tire tire) {
            this.tire = tire;
            System.out.println("Bottom init...");
        }
    }
    /*
     * 轮胎类
     * */
    static class Tire {
        private int size;
        public Tire(int size) {
            this.size = size;
            System.out.println("轮胎尺寸: " + size);
        }
    }
}

代码经过以上调整,无论底层类如何变化,整个调用链是不用做任何改变的,这样就完成了代码之间的解耦,从而实现了更加灵活,通用的程序设计了.

IoC的优势

在传统代码中创建对象顺序是: Car->Framework->Bottom->Tire

改进之后的解耦的代码的对象创建顺序是:Tire->Bottom->Framework->Car

 我们发现一个规律,通用程序的实现代码,类的创建顺序是反的,传统代码是Car控制并创建了
Framework,Framework创建并创建了Bottom,依次往下,而改进之后的控制权发生的反转,不再是使用方对象创建并控制依赖对象了,而是把依赖对象注入当前对象中,依赖对象的控制权不在由当前类控制了.

这样的话,即使依赖类发生任何改变,当前类都是不受影响的,这样是典型的控制反转,也就是IoC的实现思想.

学到这里,我们大概知道了什么是控制反转了,那么什么是控制反转呢,也就是IoC容器

这部分代码,就是IoC容器做的工作.

从上面也可以看出,IoC容器具备以下优点: 

资源不由使用资源的的双方管理,而由不使用资源的第三方管理,这可以带来很多好处.第一, 资源集中管理,实现资源的可配置和易管理.第二, 降低了使用资源双方的依赖程度,也就是我们说的耦合度.

1.资源集中管理: IoC容器会帮我们管理一些资源(对象等),我们需要使用时,只需要从IoC容器中去取就可以了.

2.我们在创建实例的时候不需要了解其中的细节,降低了使用资源双方的依赖程度,也就是耦合度.

Spring就是一种IoC容器,帮助我们来做了这些资源管理.

DI介绍

上面学习了IoC,什么时DI呢?

容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称之为依赖注入,

程序运行时需要某个资源,此时容器就为其提供这个资源.

从这点看,依赖注入(DI)和控制反转(IoC)是从不同的角度描述的同一件事情,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的耦合.

上述代码中,是通过构造函数的方式,把依赖对象注入到需要使用的对象中的

IoC是一种思想,也是"目标",而思想只是一种指导原则,最终还是要有可行的落地方案,而DI就属于具体的实现,所以也可以说,DI是IoC的一种实现.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值