Spring IoC和DI

目录

IoC

引入

传统实现思路

解决方案

IoC的优势

DI


Spring 是包含了众多⼯具⽅法的 IoC 容器.

IoC

什么是IoC?

像在类上⾯添加 @RestController 和@Controller 注解, 就是把这个对象交给Spring管理, Spring 框架启动时就会加载该类. 把对象交给Spring管理, 就是IoC思想.

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

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

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

引入
传统实现思路

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

先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底盘依赖轮⼦.

代码实现

java 复制代码
public class Main {
    public static void main(String[] args) {
        Car car = new Car(21);
        car.run();

        Car car2 = new Car(17);
        car2.run();
    }
}

//汽车
class Car {
    private Framework framework;

    public Car(int size) {
        framework = new Framework(size);
        System.out.println("framework init...");
    }

    public void run() {
        System.out.println("car run...");
    }
}

//车身
class Framework {
    private Bottom bottom;

    public Framework(int size) {
        bottom =  new Bottom(size);
        System.out.println("bottom init....");
    }
}

//底盘
class Bottom {
    private Tire tire;

    public Bottom(int size) {
        tire = new Tire(size);
        System.out.println("tire init...");
    }
}

//轮胎
class Tire {
    private int size;

    public Tire(int size) {
        System.out.println("tire size:"+size);
    }
}

上面这样的设计看起来没问题,但是可维护性却很低,因为需求可能会越来越多,比如增加轮胎颜色,修改后的代码如下:

我们可以看到,修改后的代码会报错,并且需要我们继续修改

完整代码如下:

java 复制代码
public class Main {
    public static void main(String[] args) {
        Car car = new Car(21,"aaa");
        car.run();

        Car car2 = new Car(17,"bbb");
        car2.run();
    }
}

//汽车
class Car {
    private Framework framework;

    public Car(int size,String color) {
        framework = new Framework(size,color);
        System.out.println("framework init...");
    }

    public void run() {
        System.out.println("car run...");
    }
}

//车身
class Framework {
    private Bottom bottom;

    public Framework(int size,String color) {
        bottom =  new Bottom(size,color);
        System.out.println("bottom init....");
    }
}

//底盘
class Bottom {
    private Tire tire;

    public Bottom(int size,String color) {
        tire = new Tire(size,color);
        System.out.println("tire init...");
    }
}

//轮胎
class Tire {
    private int size;
    private String color;

    public Tire(int size,String color) {
        System.out.println("tire size:"+size);
    }
}

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

程序的耦合度⾮常⾼(修改⼀处代码, 影响其他处的代码修改)。

解决方案

我们尝试改变实现方式:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋。

基于以上思路,我们把调⽤汽⻋的程序⽰例改造⼀下,把创建⼦类的⽅式,改为注⼊传递的⽅式。

完整代码如下:

java 复制代码
class Main {
    public static void main(String[] args) {
        Tire tire = new Tire(17, "red");
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
        car.run();
    }
}

//汽车
class Car {
    private Framework framework;

    public Car(Framework framework) {
        this.framework = framework;
        System.out.println("framework init...");
    }

    public void run() {
        System.out.println("car run...");
    }
}

//车身
class Framework {
    private Bottom bottom;

    public Framework(Bottom bottom) {
        this.bottom = bottom;
        System.out.println("bottom init....");
    }
}

//底盘
class Bottom {
    private Tire tire;

    public Bottom(Tire tire) {
        this.tire=tire;
        System.out.println("tire init...");
    }
}

//轮胎
class Tire {
    private int size;
    private String color;

    public Tire(int size, String color) {
        System.out.println("tire size:"+size+",color:"+color);
    }
}

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

IoC的优势

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

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

我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了.

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

到这⾥, 我们⼤概就知道了什么是控制反转了, 那什么是控制反转容器呢, 也就是IoC容器。

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

从上⾯也可以看出来, IoC容器具备以下优点:
资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。

第⼀,资源集中管理,实现资源的可配置和易管理。

第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。

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

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

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

DI

DI: Dependency Injection(依赖注⼊)
容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。

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

从这点来看, 依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。

前面代码中, 是通过构造函数的⽅式, 把依赖对象注⼊到需要使⽤的对象中的。

IoC 是⼀种思想,也是"⽬标", ⽽思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就属于具体的实现。所以也可以说, DI 是IoC的⼀种实现.

相关推荐
Open Source Thoughts1 小时前
OpenClaw.ai:Agentic AI 时代的“SpringFramework”时刻
java·人工智能·spring·prompt·开源软件·agi·ai-native
forestsea1 小时前
优雅终结启动顺序噩梦:ObjectProvider —— Spring 4.3 开始引入
java·后端·spring
小楼v1 小时前
⭐解锁RAG与Spring AI的实战应用(万字详细教学与完整步骤流程实践)
java·后端·rag·spring ai·ai大模型应用
想不明白的过度思考者1 小时前
JavaEE进阶 ——【SpringBoot 快速上手】从环境搭建到HelloWorld实战
java·spring boot·spring·java-ee
那我掉的头发算什么1 小时前
【SpringBoot】一篇文章讲清楚拦截器所有知识
java·spring boot·后端·spring
he___H2 小时前
抽象工厂模式
java·抽象工厂模式
mjhcsp2 小时前
C++ 后缀平衡树解析
android·java·c++
望舒5132 小时前
代码随想录day33,动态规划part2
java·算法·leetcode·动态规划
追随者永远是胜利者3 小时前
(LeetCode-Hot100)169. 多数元素
java·算法·leetcode·go