1. Spring的3个核心概念
Spring是个框架技术,其有3个核心的概念:控制反转(IOC)、依赖注入(DI)和面向切面编程(AOP)。
spring的其他技术都是依赖这三个核心技术建立起来的,因此学习spring,首先应该了解这三个技术。
AOP后续再讲,此处先讲解IOC和DI。
2. 通过实操引出spring的真身
2.1 如何水平组装两个对象?
假设现在有两个Class,A和B,如下:
ClassA{
public void testA(){}
}
ClassB{
public void testB(){}
}
现在我们想实现一种场景:调用A对象的testA方法去实现某些功能,但是testA方法需要借助B对象的testB方法去实现该功能。
嗯….对,这就是我们之前了解的委托机制。
所以,应该改造如下:
ClassA{
private ClassB classB;
public ClassA(){
this.classB = new ClassB();
}
public void testA(){
this.classB.testB();
}
}
上面改造后的代码就是我们掌握的委托机制的一种,即 A类中定义一个B类型的成员,以成员变量的方式接收B对象,A类自己实例化B对象,即以成员变量的方式内建B对象。
- ClassA类中声明一个ClassB类型的成员变量,用于接收ClassB对象。
- ClassA类中自己new一个ClassB对象,然后注入给成员变量classB,即通过内建的方式创建ClassB对象。
- ClassA中的testA方法委托classB对象的testB方法去实现业务逻辑。
像这种操作我们已经很熟悉了,称为A对象委托B对象、A对象依赖B对象、A对象注入了B对象等等。
所以,此时的组合中,A对象和B对象之间就是依赖关系,即A对象依赖B对象。
- ClassA对象依赖的ClassB对象,被写死在ClassA的构造方法里了,此时如果想让ClassA依赖其他的对象,无能为力。
- 代码不利于测试,如果想测试ClassA依赖不同的classB对象,只能修改ClassA的构造方法了。
我们需要通过另外一种委托方式:A类中定义一个B类型的成员,以成员变量的方式接收B对象,外部向A类注入B对象,即以成员变量的方式注入B对象。
这种方式更灵活一点:
ClassA{
private ClassB classB;
public ClassA(ClassB classB){
this.classB = classB;
}
public void testA(){
this.classB.testB();
}
}
上面的方式,将被委托者classB的创建由ClassA负责内建交给了外部使用者进行传入,即ClassB对象的控制权交给了使用者,如下:
// classB对象的创建交给了外部使用者负责,使用起来更加灵活,不用修改ClassA的构造方法了。
ClassB classB = new ClassB();
ClassA classA = new ClassA(classB);
classA.testA();
上面的方式看似没问题了,但是,如果现在ClassA需要注入ClassC,ClassD,ClassE等等,都按上面那种方式来的话,那么使用ClassA时候就成了下面那样了:
ClassB classB = new ClassB();
ClassC classC = new ClassC();
ClassD classD = new ClassD();
ClassE classE = new ClassE();
...
ClassA classA = new ClassA(classB,ClassC,ClassD,ClassE,....);
classA.testA();
也就是说,使用者在使用ClassA的testA()方法之前,就需要先将classA对象依赖的所有对象都给创建好,然后再将这些对象注入到classA对象中。
这样一来,代码量比较大,不好维护;如果classA又依赖了其他对象,还得重载构造方法,使用方还得创建好然后注入等等。
有没有什么好的方式改造这种呢?
我们看到ClassA依赖的对象有很多,这些被依赖的对象的创建都是由使用者负责实例化并且组装到ClassA对象中的。那么实例化这些被依赖的对象并且组装其到ClassA对象中的过程,能不能找一个第三方把这个事情做了?
比如,我只需要提供给第三方一个清单,这个清单上列着我当前需要ClassA对象,并且ClassA对象需要依赖的一对B对象C对象等等,然后第三方就会根据这份清单帮我创建好ClassA对象,并且组装ClassA对象依赖的那些对象。
当我需要使用classA对象时,只需要向第三方发起一个查找请求,如果第三方有classA对象,直接将其内部组装好的classA对象返回即可。
因此,如果有第三方帮我们实例化对象并且组装对象之间的依赖关系的话,我们在使用对象时只需要向第三方发起查找请求即可。
当我们想要调整依赖关系时,只需要修改清单。
很幸运,这个事情,spring帮我们做了。
2.2 啥是spring容器你懂么?
容器这个概念特别好,起的很恰当,就跟我们使用水杯装水、使用饭盒装饭一样,水杯和饭盒就是容器。
spring在启动时会在JVM内存中开辟一个很大的缓存空间,这个空间就是spring容器。
spring容器里面能够装很多东西,我们给spring容器一个清单,清单中列出我们需要创建的对象和与其他对象之间的依赖关系,spring容器就会帮我们创建并组装好清单中的对象,然后将这些对象缓存在spring容器中。
当我们需要使用这些对象的时候,只需要向spring容器发起查找请求,spring容器就会返回给我们指定的对象供我们使用。
因为spring容器往往是缓存一些实例化好的bean和有依赖关系的bean实例,这些都是IOC的过程,因此,spring容器也叫做IOC容器。
3. IOC和DI?
3.1 IOC:控制反转
我们之前使用ClassA对象,都是自己负责去创建并组装其与其他对象的依赖关系,而现在这些过程都交给Spring容器帮我们完成了。
当我们使用某个对象时,只需要去spring容器中查找就行了。
也就是说,目标对象和其依赖关系的创建过程被反转了,之前是开发者自己负责,现在反转给了spring容器去操作。
所以叫做控制反转。
IOC是面向对象编程中的一种设计原则,目的是为了降低对象创建和依赖之间的耦合度,让系统更利于扩展和维护。
3.2 DI:依赖注入
spring容器帮我们创建目标对象和其依赖的对象,创建好了之后会将这种依赖关系进行注入。
比如 ClassA对象依赖ClassB和ClassC,那么Spring帮我们创建好ClassA、ClassB、ClassC对象之后,会将ClassB和ClassC对象注入到ClassA对象中。
即,依赖注入,注入的是对象之间的依赖关系。
4. 总结
1.IOC控制反转,是一种设计理念,将对象创建和组装的主动控制权利交给了spring容器去做,控制的动作被反转了,降低了系统的耦合度,利于系统维护和扩展,主要就是指需要使用的对象的组装控制权被反转了,之前是自己要做的,现在交给spring容器做了。
2.DI依赖注入,表示spring容器中创建对象时给其设置依赖对象的方式,通过某些注入方式可以让系统更灵活,比如自动注入等可以让系统变的很灵活,这个后面的文章会细说。
3.spring容器:主要负责容器中对象的创建、组装、对象查找、对象生命周期的管理等等操作。
文档信息
- 本文作者:Marshall