什么是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 却可以实现自动、动态的注入依赖。