白话Spring -- Spring IOC
白话Spring -- Spring IOC
笔者虽然看过不少的技术博客,也用过Spring写过一年的代码,也修改过BUG,但是还是不理解到底什么是Spring?
PS:不知道大家有没有同感,不是技术博客看不懂,那些个IOC、AOP也是能看懂,但就是感觉没有真正的理解透彻,总感觉还是有一层薄雾笼罩着,从而没办法随心所欲的使用Spring。
笔者现在就通过这一系列文章,具象化的、图形化的说一下我对Spring的理解,不仅是对大家的一点帮助,也是笔者记录自己的心得感受,以免以后忘记了。
本文将通过:
- Spring是个啥?
- Spring-IOC是个啥?
- Spring-IOC能干啥?
- 为什么要用Spring?
- Spring怎么使用的?
这几点来讲解一下我理解中的Spring。
1. Spring是个啥?
度娘上和各种博客上都说Spring是一个Java开发框架,能方便我们开发代码,松耦合,方便实现各种功能。巴拉巴拉,各种各种。。。
等会儿,我们先别管其他的。看到能简化代码,松耦合。嗯,这就是Spring。其他的什么框架什么的,管它呢,等我以后对Spring熟了再说吧。人脸都没看清,还指望我能对她能有多深入了解,对吧。
2. Spring-IOC是个啥?
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。 --百度百科
上面是百度百科的解释,但是看了之后还是一头雾水。到底啥是IOC,怎么实现的呢?那么我们就来对比一下吧。
我们大家以前写代码,一个类(Test)要引用另外一个类(Car)都是下面这样的:
// 代码块1
public class Car{
private String name = "兰博基尼";
public String getCarName(){
return this.name;
}
}
public class Test{
Car car = new Car();
public void test(){
System.out.println("我获得了一辆" + car.getCarName());
}
}
我们先理解一下这句话 Car car = new Car();
就是先声明一个Car
类型的变量:car
,然后再创建一个Car
类型的实例赋值给 car
,也就是说这个car
只是一个模子,用来存放这个实例的,我们使用的时候直接把car
当成那个实例使用。
大家可能会想这个东西很简单呀,为什么还要拿出来再说一遍?放心,这里我们待会儿就能用到。
那么,我们来整体理解一下这段代码,就是Test
类创建了Car
类的实例,并调用了Car
类的方法。也就是说,Test
类是主动的去创建Car
类的。
那么,如果我们使用Spring-IOC呢?
咱现在还不知道Spring-IOC到底是个啥,既然说能帮我们创建实例,那么咱现在就暂时把Spring-IOC理解成为"哆啦A梦"的百宝囊,我们要什么,Spring就能提供什么。
那么我们接下来的代码就能这样写:
// 代码块2
public class Car{
private String name = "兰博基尼";
public String getCarName(){
return this.name;
}
}
public class Test{
Car car;
//此处假设Spring可以把实例赋值给car,但具体内容暂时忽略,后面会讲
public void test(){
System.out.println("我获得了一辆" + car.getCarName());
}
}
大家看到这段代码肯定一脸懵。这是啥,怎么变量car
都没有赋值,值为null,就能调用方法了?不会报异常嘛。
大家稍等片刻,别急别急,慢慢来。上面的是伪代码,不能被执行的。我在这里是先讲一下Spring-IOC能给我们做到什么效果。而Spring-IOC也确实可以自己创建一个Car
类实例然后赋值给car
变量。只是这些都是在后台执行的,我们看不到。所以我们在这里就索性认为Spring可以直接给变量赋值实例。也就是说到这里,car
里就是有实例的,不是null。至于这里的代码怎么写,Spring-IOC怎么实现的,本文的后面会一一讲述。
也就是说:Spring帮助Test
类创建了实例然后又交给了Test
类使用,而不用Test
类自己去创建所需要的实例。换句话说,就是创建Car
类实例的主动权由Test
类变成了Spring。那么,我们这里就出现了一个概念:控制反转(IOC):将本来应由JavaBean(即Java类)创建实例的主动权交给了Spring,让Spring来创建实例,再将实例交给JavaBean使用。这种创建实例的控制权的改变,就称为控制反转。
那么,这玩意儿有啥用?
3. Spring-IOC能干啥?
通过上面的代码块1-2,我们并不能看出来什么,那么我就新写一个例子:
这个例子是两个类实现了一个接口,然后实现一种多态的方式调用Car
接口的实现类的实例。下面是我们以前的写法:
//代码块3
public interface Car{
public String getCarName();
}
public class BaoShiJie implements Car{
private String name = "保时捷";
public String getCarName(){
return this.name;
}
}
public class FaLaLi implements Car{
private String name = "法拉利";
public String getCarName(){
return this.name;
}
}
public class Test{
Car car = new FaLaLi();
// Car car = new BaoShiJie();
public void test(){
System.out.println("我获得了一辆" + car.getCarName());
}
}
从上面可以看出,如果我们想从"法拉利"改成"保时捷",需要修改Test
的代码,将创建FaLaLi
类的实例修改成创建BaoShiJie
类的实例。每一次改变都需要修改一次,如此大动干戈,显然这种方式不太好。
那么,使用Spring-IOC呢?
我们在代码块2中假设了,Spring-IOC可以直接给变量赋值实例,那么代码块3中的car变量我们是否也可以通过这种方式赋值呢?有人可能会思考,即使可以,那程序怎么分辨我们具体要什么车呢?如此是否我们同样能假设我们可以告诉Spring-IOC我们需要哪一辆呢?
// 代码块4
public interface Car{
public String getCarName();
}
public class BaoShiJie implements Car{
private String name = "保时捷";
public String getCarName(){
return this.name;
}
}
public class FaLaLi implements Car{
private String name = "法拉利";
public String getCarName(){
return this.name;
}
}
public class Test{
Car car;
// 此处告诉Spring-IOC我需要法拉利/保时捷,假设Spring-IOC就会把相应车的实例赋值给变量car
public void test(){
System.out.println("我获得了一辆" + car.getCarName());
}
}
哦哦哦,出来了,大家发现没有,Test
类里没有出现FaLaLi
类或者BaoShiJie
类的身影,我们告诉Spring-IOC我们需要什么车,完全可以通过String的方式,如果这个String还是通过外部参数形式导入的话,那么我们在换车的时候,就完全不同修改Test
类了。