Spring概念:
通常所说的Spring指的是Spring Framewprk(Spring框架),它是一个开源的框架。用一句话概括就是:Spring是包含了众多工具方法的IoC容器。
什么是容器?
容器是用来容纳某种物品的装置,在之前的学习中,我们接触到的容器有List/Map(数据存储容器)、Tomcat(Web容器)。
什么是IoC容器?
Spring就是一个IoC容器,IoC(Inversion of Control)翻译成中文就是“控制反转”的意思,也就是说,Spring是一个“控制反转”的容器。
如何理解控制反转?
以前我们在一个类中使用另外一个类,需要New一个对象来使用,所以对象的生命周期是由当前代码或程序员来控制;控制反转其实是控制权反转,也就是说对象的生命周期,不由程序员或当前代码片段来控制,而是由Spring(Spring容器/IoC容器)来控制,这就叫做控制权反转。
为什么要使用IoC容器/Spring?
使用IoC容器最大的优点:可以实现解耦(松耦合)。
如何理解?我们可以想象成要造一辆车,要造这辆车得依赖于车身,车身又依赖于底盘,底盘依赖于轮胎。就像下面这张图所示:
下面我们用代码来演示这种关系:
传统的开发方式
- 我们新建一个类,叫Car,这个类里面有一个init()方法,可以理解成造车的关键步骤,Car依赖于Framework类。
package old;
public class Car {
private Framework framework;
public Car(){
this.framework=new Framework();
}
public void init(){
System.out.println("执行了 Car init方法");
//依赖车身
framework.init();
}
}
- 接着new一个Framework类,Framework依赖于Bottom。
package old;
public class Framework {
private Bottom bottom;
public Framework(){
this.bottom=new Bottom();
}
public void init(){
System.out.println("执行了 Framework init 方法");
//依赖底盘
bottom.init();
}
}
- Framework又依赖于Bottom,于是我们再new一个Bottom类
package old;
public class Bottom {
private Tire tire;
public Bottom(){
this.tire=new Tire();
}
public void init(){
System.out.println("执行了 Bottom init 方法");
//依赖轮胎
tire.init();
}
}
- 最后new一个Tire类,定义属性size
package old;
public class Tire {
private int size=20;
public void init(){
System.out.println("执行了Tire init 方法,Size:"+size);
}
}
- new一个Test类,测试一下代码是否正确:
package old;
public class Test {
public static void main(String[] args) {
Car car=new Car();
car.init();
}
}
执行没有问题,上面的代码就是传统开发的过程。
但是如果对车的要求增加了,比如对于轮胎的size,不同的人群,对轮胎size大小要求不一样,在代码上体现就是不能再使用原来默认的size,我们Tire类中重载构造方法。
package old;
public class Tire {
private int size=20;
public Tire(int size){
this.size=size;
}
public void init(){
System.out.println("执行了Tire init 方法,Size:"+size);
}
}
但是这样会引发一系列的问题,Tire的构造方法是有参的,而Bottom又依赖于Tire,Bottom类也要随之改动,不然就会报错,就像下面这样:
我们先给Bottom补上需要的参数:
package old;
public class Bottom {
private Tire tire;
public Bottom(int size){
this.tire=new Tire(size);
}
public void init(){
System.out.println("执行了 Bottom init 方法");
tire.init();
}
}
Bottom中本身是没有参数size的,这里要改这个报错,需要传入size,于是这个size由Framework传入。Framework本身也没有size参数,于是需要Car传给它。
package old;
public class Framework {
private Bottom bottom;
public Framework(int size){
this.bottom=new Bottom(size);
}
public void init(){
System.out.println("执行了 Framework init 方法");
//依赖底盘
bottom.init();
}
}
当我们改完Framework类后,Car类也会出现问题,缺少size参数,我们重载Car的构造方法,进行有参构造传入size.
package old;
public class Car {
private Framework framework;
public Car(int size){
this.framework=new Framework(size);
}
public void init(){
System.out.println("执行了 Car init方法");
//依赖车身
framework.init();
}
}
然后我们在测试类中新建Car对象的时候设置size大小进行测试,我们把size设置成10:
package old;
public class Test {
public static void main(String[] args) {
Car car=new Car(10);
car.init();
}
}
这样就可以随便设置轮胎size的大小,满足不同人群的需求。通过上面的代码可以可以看出,当我们最底层的代码发生改变时,整个调用链上的所有代码都需要改动,而且这只是改一个参数。那如果我们需要加别的参数并且做更改呢?这就非常麻烦,底层的代码改变,调用链上的所有代码都要跟着改变,这就是耦合———“牵一发而动全身”!
怎么解决这个问题呢?用IoC框架,使用IoC就可以实现解耦,就可以避免上面的问题。
IoC开发方式
- 编写Car类,Car类依然依赖于Framework类,但是不同的是,我们使用Framework对象时不需要new了,直接声明一下,框架会给我们。
package ioc;
public class Car {
private Framework framework;
public Car(Framework framework){
this.framework=framework;
}
public void init(){
System.out.println("Car init");
framework.init();
}
}
- 编写Framework类,Framework依赖于Bottom,但是这里同样也没有new Bottom对象,同样是框架给我们的Bottom对象,直接去使用。
package ioc;
public class Framework {
private Bottom bottom;
public Framework(Bottom bottom){
this.bottom=bottom;
}
public void init(){
System.out.println("Framework init");
bottom.init();
}
}
- 编写Bottom类,Bottom依赖于Tire ,这里也没有new Tire对象,调用Tire时直接去框架中去取,然后给当前变量设置框架里面的bottom。
package ioc;
public class Bottom {
private Tire tire;
public Bottom(Tire tire){
this.tire=tire;
}
public void init(){
System.out.println("Bottom init");
tire.init();
}
}
- 编写Tire类,设置属性和init方法
package ioc;
public class Tire {
private int size=15;
public Tire(){}
public void init(){
System.out.println("Tire init,size:"+size);
}
}
- 编写单元测试代码,这里是模拟Spring框架(不用关注这里的new对象),这是框架的事情。
package ioc;
public class Test {
private Tire tire;
private Bottom bottom;
private Framework framework;
private Car car;
public Test(){
this.tire=new Tire();
this.bottom=new Bottom(this.tire);
this.framework=new Framework(this.bottom);
this.car=new Car(this.framework);
}
public static void main(String[] args) {
Test test=new Test();
test.car.init();
}
}
然后我们给Tire设置size,将无参构造改成有参构造。
package ioc;
public class Tire {
private int size=15;
public Tire(int size){
this.size=size;
}
public void init(){
System.out.println("Tire init,size:"+size);
}
}
修改后整个调用链上的代码没有报错,调用链上的代码也不需要任何修改,Tire改动后哪里需要修改是Spring框架/IoC容器的事情,跟用户没有任何关系,Spring会自动去设置这些参数。
总结一下就是IoC帮我们实现了业务代码的解耦,实现了松耦合。不在是底层代码发生改变,整个调用链上的代码都要改变。这就是IoC的优点,实现解耦!