一、Spring的定义和作用?
- 定义:用一句比较简短的话来描述:Spring是一个容器框架,是一个用于配置和管理bean之间的关系的轻量级框架;
- 作用:控制反转Ioc(Inversion of Control),面向切面编程AOP(Aspect Oriented Programming),现成的可复用组件,便利了与其他框架的集成等。
二、Spring在Web应用中作用的层次?
小结:Spring接管了Web应用的各个层次,至于如何配置和管理组件请往下参见Spring提供的Ioc功能。这便体现了容器框架了。
三、Spring提供的Ioc功能
- 控制反转Ioc:控制反转指的是把传统上由程序代码直接创建和管理对象的职责移交给容器。具体有依赖注入和依赖查找两种方式。
- 示例:有一个Student(name,Teacher)类,一个Teacher(name)类。现在需要创建一个Student对象。我们来比较一下这两种做法。
传统:
Teacher teacher=new Teacher();
teacher.setName("老师");
Student student=new Student();
student.setName("学生");
student.setTeacher(teacher);
Spring:
<bean id="student" class="test.Student">
<property name="name" value="学生"/>
<property name="teacher" ref="teacher"/>
</bean>
<bean id="teacher" class="test.Teacher">
<property name="name" value="老师"/>
</bean>
分析1:第二种方法中我们配置了一个Student对象和一个Teacher对象,并为其注入了属性,其中Student的teacher属性指向了我们定义的Teacher对象。Spring会将这两个对象管理起来,并且将Teacher对象注入到Student对象中。现在应该稍微能够理解Spring是配置和管理bean的容器框架了吧?
分析2:那么Spring煞费苦心为我们做了这事情有什么作用呢?或者说控制反转有什么作用?
写过稍大一点的程序的人应该很有体会,到了后面,其实程序很不好扩展,不好维护。对于企业级应用更是可能出现内存管理有关的问题,十分难以排查和维护。这是我们因为代码中存在大量的重复工作用来创建具体的实现,与具体耦合了!还以上面的例子为例,现假设Student和Teacher都实现了Person接口
在传统的方式中,我们假设代码中有1000个地方出现了Person person = new Student()这个语句,接着调用person接口中的方法。有朝一日,我们想要将Student换成Teacher对象?怎么办??我们不得不对这1000处都做修改,换成Person person = new Teacher(),想想都害怕。那么假如我们用了Spring呢?那么我只要在配置文件中将person对象的实现类替换成Teacher类即可,那么对于其他依赖于person对象的类,都会得到新的Teacher对象而非Student对象。也就是说,使用Spring可以让我们方便地替换抽象的具体实现! 这类似于工厂模式。
分析3:控制反转的缺点
一种技术不可能是十全十美的,必定是有所权衡,控制反转亦是。首先,相比于直接使用new创建对象,使用Spring配置bean对象时底层框架需要使用到反射机制,这必然会带来一定的性能损耗;其次,假如我们重构的时候修改了类的路径(改了包名等),那么必须手动去XML文件中修改。
四、Spring提供的AOP功能
先提一下编程语言的发展历程,机器语言->汇编语言->面向过程的高级语言->面向对象的高级语言。可以看出,这是逐渐抽象和封装的过程。到了面向对象,已经能够以对象维度进行编程,现在要提到的是更上维度的面向切面编程。什么是切面呢?切面是应用中的交叉功能,也即是多次重复出现的同场景下的功能。比如需要在每次方法调用的时候打印日志,这种情况下假如我们还用面向对象的粒度去思考和编程,那么在每次方法调用时必然很累赘,会出现以下重复的模式,这样系统是难以维护的:
public void method(){
//方法调用前的日志打印
// TODO: 2016/11/11 业务逻辑
//方法调用后的日志打印
}
AOP要做的事情就是将这些重复的逻辑抽离出来,怎么做呢?其实看到上面的场景,很多人就能想到代理模式了,不错,这正是Spring采用的方法。Spring可以给我们返回代理对象,实际的业务逻辑Spring会交由实际对象处理,方法调用前后的其他逻辑代码由代理对象执行。这样就能实现在方法调用的前后做一些通用的工作了(比如打日志,统计方法调用时间,事务管理等)。
当然仅有代理模式是不足的!因为Spring还需要知道需要代理的具体方法(你有时候并不是所有的方法都需要打印日志),这个时候就需要我们帮助Spring选择了。Spring提供了注解、XML多种方法帮助我们声明需要被代理的方法。AOP的具体使用后面的文章会提到。
五、Spring提供的现成可复用的组件和便利的框架集成
我们可以发现,Web应用基本上都会有一些通用的功能,会有许多相似的代码。于是Spring将这些功能封装起来,只要我们需要,就可以将相应的bean配置到上下文中,那么这个组件就成为了受Spring容器管理的bean,可以通过其API使用其功能。
除了Spring提供的组件,Spring还人性化地为我们考虑到了更多的可能,允许我们集成一些优秀成熟的框架。以Hibernate为例,我们只要下载其jar包之后,将需要使用到的组件注册到Spring上下文中,那么就可以在应用中使用Hibernate的ORM映射功能。