Spring是什么?IoC是什么?DI又是什么?
Spring是什么?
Spring
指的是Spring Framework(Spring框架)
,是包含了众多工具方法的IoC容器。
1.什么是容器?
Spring
是包含了众多工具方法的IoC容器
。那么这里的容器是什么意思?很好理解,容器就是要能装东西、取东西,就好比如水杯、背包、还有数据结构中的Map、List等。那么Spring
也是可以装东西、取东西,不过这里的这个“东西”就是java中的对象。(后文介绍)
没错,Spring
就是装对象
的容器。(至于怎么存取对象,这里先不作讨论,本篇先注重其概念,详细的后面会更新。)
2.什么是IoC?
IoC容器
中的IoC
是什么呢?IoC
的全称是Inversion of Control
,意思是“控制反转”,“控制反转”又是什么?我们通过下面的案例来慢慢体会“控制反转”是什么?
2.1 传统编程方式
案例:制造自行车。

要想造出一辆自行车必须要依赖轮子才能跑,轮子需要链条来转动,而链条需要脚踏板来牵引。
//自行车
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();
}
}
结果:脚踏板的边长:长方形
上面的方式,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的, 这样就解耦了。

2.3 再来理解IoC
我们用上面的案例来理解,我们来对比两种方式的类的创建顺序:
第一种方式是先创建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
的:
(ps:如有错误请在评论区指出,谢谢~)
转载自:https://juejin.cn/post/7222484074481434679