1. IoC & DI ⼊⻔
1.1 Spring 是什么
通过前⾯的学习, 我们知道了Spring是⼀个开源框架, 他让我们的开发更加简单. 他⽀持⼴泛的应⽤场 景, 有着活跃⽽庞⼤的社区, 我们⽤⼀句更具体的话来概括Spring, 那就是: Spring 是包含了众多⼯具⽅法的 IoC 容器
1.1.1 什么是容器
所谓容器,是⽤来容纳某种物品的装置,我们之前学到的数据结构中 List/Map -> 数据存储容器 ; 服务器开发中Tomcat -> Web 容器;
1.1.2 什么是 IoC 容器
IoC是Spring的核心思想。
其实IoC在前面的代码练习已经使用过了,比如在类上面添加 @RestController 和 @Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时,就会加载该类。
故此,把对象交给Spring管理,这就是IoC思想。
IoC:Inversion of Control(控制反转),也就是说Spring是一个“控制反转”的容器。
所谓控制反转,就是控制权反转,也就是程序获得依赖对象的过程被反转了;
简单来说就是当需要某个对象时,把创建对象的任务交给容器,程序中只需要依赖注入(Dependency Injection,简称DI)就可以了。这个容器称为:IoC容器。Spring是一个IoC容器,所以有时也称为Spring容器。(传统开发模式需要自己通过 new 创建对象,现在不需要再进行创建了,引入了Ioc思想之后,我们就不需要自己进行创建对象了)
2. IoC介绍
下面通过案例来介绍什么是IoC,现在需求:造一辆车;
2.1 传统程序开发
我们是实现思路是这样的:先设计轮子(Tire),然后根据轮子的大小设计底盘(;),接着根据底盘设计车身(FrameWork),最后根据车身设计好整个汽车(Car)。这里就出现了一个 “依赖” 关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子。如图:
代码如下:
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.run();
}
}
public class Car {
private FrameWork frameWork;
public Car() {
frameWork = new FrameWork(17);
System.out.println("frameWork init....");
}
public void run() {
System.out.println("Car run...");
}
}
public class FrameWork {
private Bottom bottom;
public FrameWork(int size) {
bottom = new Bottom(size);
System.out.println("Bottom init...");
}
}
public class Bottom {
private Tire tire;
public Bottom(int size) {
tire = new Tire(size);
System.out.println("Tire init....");
}
}
public class Tire {
private int size;
public Tire(int size) {
this.size = size;
}
}
运行结果如下:
如果有新的需求了,要修改轮胎的颜色,那就要多添加一个属性,那么传参的时候,Car类、FrameWork类、Bottom类、Tire类的构造函数都要多添加一个元素,传参也要多传一个颜色属性。这样的话,耦合就很高了;而这也只是简单的给轮胎添加一个属性,随着项目需求的增加,项目也会越来越复杂,现在的代码可维护性也很差,就不太合适了。所以,要进行改进。
2.2 解决方案
上面的程序中,我们是根据轮胎的尺寸设计底盘的,轮胎的尺寸已改,底盘的设计也就得改,而车身依赖底盘,就会导致一连串的问题,几乎整个设计都得改。
现在换一种思路,我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘设计轮胎。这时候,依赖关系就反转过来了:轮胎依赖底盘,底盘依赖车身,车身依赖汽车。
这就类似于我们造一辆完整的汽车,如果所有的配件都是自己造,那么客户需求发生改变的时候,比如轮胎尺寸不再是原来的尺寸了,那我们就要自己手动来改了,但如果把轮胎外包出去,那么即使轮胎的尺寸发生改变,那么我们只需要向代理工厂下订单就行了,我们自身是不需要出力的。
关于如何实现这种设计开发思想,我们可以尝试不在每个类中创建下级类,如果自己创建下级类就会出现当下级类发生改变操作,自己也要跟着修改。此时我们只需要将原来有自己创建的下级类,改为注入的方式,因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修改任何代码,这样就完成了程序的解耦。
2.3 IoC程序开发
我们根据新的设计开发思想把调用汽车的程序改造一下,把创建子类的方式,改为注入传递的方式。具体代码如下:
public class Main {
public static void main(String[] args) {
Tire tire = new Tire(17);
Bottom bottom = new Bottom(tire);
FrameWork frameWork = new FrameWork(bottom);
Car car = new Car(frameWork);
car.run();
}
}
public 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...");
}
}
public class FrameWork {
private Bottom bottom;
public FrameWork(Bottom bottom) {
this.bottom = bottom;
System.out.println("Bottom init...");
}
}
public class Bottom {
private Tire tire;
public Bottom(Tire tire) {
this.tire = tire;
System.out.println("Tire init....");
}
}
public class Tire {
private int size;
public Tire(int size) {
this.size = size;
System.out.println("size:" + size);
}
}
如此,如果轮胎需要修改尺寸,或者添加一个属性,只需要修改Tire类就好了,其他类不需要修改,即达到了解耦的效果。
2.4 IoC优势
在传统代码中的对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car,如下图所示:
我们发现,程序的实现代码顺序和类的创建顺序是反的,传统代码是Car控制并创建了Framework,Framework的创建也会继续创建Bottom,依次往下递推,而改进后的控制权发生了反转,不再是使用方创建对象并控制依赖对象了,而是把依赖对象注入到当前对象中,依赖对象的控制权不再由当前类控制。这样的话,即使依赖类发生任何改变,当前类都是不受影响的,这就是典型的控制反转,也是IoC的实现思想。
而控制反转容器也就是IoC容器,如图:
上面容器中的代码就是IoC容器做的工作。
由此可以看出,IoC具有以下优点:资源不由使用资源的双方管理,而由使用资源的第三方管理,这可以带来很多好处。
第一,资源集中管理,实现资源的可配置和易管理。
第二,降低使用资源双方的依赖程度,也就是我们说的耦合度。
资源集中管理:IoC容器会帮我们管理一些资源(对象等),我们需要使用时,只需要从IoC容器中去取就可以了。
解耦合:我们在创建实例的时候不需要了解其中的细节,降低了使用资源双方的依赖程度,也就是耦合度。
而Spring就是一种IoC容器,帮助我们来做了这些资源管理。
3. DI介绍
DI:Dependency Injection(依赖注入);容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称为依赖注入。
程序运行时,需要某个资源,此时容器就为其提供这个资源。从这点来看,依赖注入(DI)和 控制反转(IoC)是从不同的角度描述同一件事,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦。
上面改进后的代码,就是通过构造函数,把依赖对象注入到需要使用的对象中。如图:
IoC是一种思想,也是 “目标”,而思想只是一种指导原则,最终还是要有可行的落地方案,而DI就属于具体的实现。所以也可以说,DI是IoC的一种实现。
ps:本次的内容就到这里了,如果对你有所帮助的话,就请一键三连哦!!!
本文的封面来自:bilibili苏杉杉的pv,侵权删 url:https://www.bilibili.com/video/BV1vo4y167eh/?spm_id_from=333.999.0.0&vd_source=866da5be2ef0ddd213b053523da53138
————————————————
电子签名:上嘉路