来个web框架发展史
Spring 由来
2002年,Rod Johnson编著出版了《Expert one to one J2EE design and development》,该书中对JavaEE框架臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求探索革新之道。以此书为指导思想,他编写了interface21框架,这是一个力图冲破J2EE传统开发的困境,从实际需求出发,着眼于轻便、灵巧,易于开发、测试和部署的轻量级开发框架。
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,2003年推出Spring1.0测试版。
2004年3月24日,发布了1.0正式版。同年Rod Johnson又推出了一部堪称经典的力作《Expert one-to-one J2EE Development without EJB》,该书在Java世界掀起了轩然大波,不断改变着Java开发者程序设计和开发的思考方式。在该书中,作者根据自己多年丰富的实践经验,对EJB的各种笨重臃肿的结构进行了逐一的分析和否定,并分别以简洁实用的方式替换之。至此一战功成,Rod Johnson成为一个改变Java世界的大师级人物。
传统J2EE应用的开发效率低,应用服务器厂商对各种技术的支持并没有真正统一,导致J2EE的应用没有真正实现“一次编写,到处运行”的承诺。Spring作为开源的中间件,独立于各种应用服务器,甚至无须应用服务器的支持,也能提供应用服务器的功能,如声明式事务、事务处理等。Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring是企业应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。然而,Spring并不想取代那些已有的框架,而是与它们无缝地整合。
2006年,推出Spring2.0;
- 2007年,推出Spring2.5;
- 2008年,推出Spring3.0;
- 2011年,推出Spring3.1;
- 目前,Spring最新版本是Spring4。
Spring 框架
Spring 主要一个通过IoC容器降低模块之间耦合度的框架。
下图显示了Spring框架的结构。
- IoC Container: 这是最重要的,也是最基础的, Spring的基础。它的作用是配置和Java对象的生命周期管理。这篇文章中我们将学习这一部分。
- DAO, ORM, AOP, WEB: 各个模块可用于当工具或框架集成到了Spring中。
理解Spring框架,一定要理解其核心思想:控制反转(IoC)
IoC理论的背景
我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。
图1:软件系统中耦合的对象
如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针、分针和秒针顺时针旋转,从而在表盘上产生正确的时间。
图中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务。
我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组的正常运转。
齿轮组中齿轮之间的啮合关系,与软件系统中对象之间的耦合关系非常相似。
对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础。现在,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。
图2:对象之间复杂的依赖关系
耦合关系不仅会出现在对象与对象之间,也会出现在软件系统的各模块之间,以及软件系统和硬件系统之间。
如何降低系统之间、模块之间和对象之间的耦合度,是软件工程永远追求的目标之一。
为了解决对象之间的耦合度过高的问题,软件专家Michael Mattson提出了IoC理论,用来实现对象之间的“解耦”,目前这个理论已经被成功地应用到实践当中,很多的J2EE项目均采用了IOC框架产品Spring。
什么是控制反转(IoC)
控制反转(Inversion of Control,英文缩写为IoC)
1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IoC 这个概念。
对于面向对象设计及编程的基本思想,前面我们已经讲了很多了,不再赘述,简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。
IoC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦。
图3:IOC解耦过程
大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IoC容器,所以,IoC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IoC容器比喻成“粘合剂”的由来。
我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:
图4:拿掉IoC容器后的系统
我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容,只要创建相应的对象了。
这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。
所以,如果真能实现IoC容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!
我们再来看看,控制反转(IOC)到底为什么要起这么个名字?
控制反转是,原来主动获取他所依赖的对象的引用,现在,变成被动获取他所依赖的对象的引用,这个责任的反转。
那么怎么将主动变为被动呢?
这就是借助“第三方”来统一管理所有的对象。这个“第三方”在Spring里叫IoC容器,对象的查找、定位和创建全部由IoC容器来管理。
通俗点说就是不创建对象。以前我们要调用一个对象的方法,首先要new一个对象。但使用IoC容器,在代码中不直接与对象连接,而是在xml配置文件中描述要使用哪一个对象。容器负责将这些联系在一起。
控制反转的实现方法有两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛,Spring 就是采用依赖注入。
所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
IoC模式,系统中通过引入实现了IoC模式的IoC容器,即可由IoC容器来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分开。其中一个特点就是通过文本的配置文件进行应用程序组件间相互关系的配置,而不用重新修改并编译具体的代码。
IoC中最基本的Java技术就是“反射”编程。反射又是一个生涩的名词,通俗的说反射就是根据给出的类名(字符串)来生成对象。这种编程方式可以让对象在生成时才决定要生成哪一种对象。
我们把依赖注入应用到软件系统中,再来描述一下这个过程:
对象A依赖于对象B,当对象 A需要用到对象B的时候,IoC容器就会立即创建一个对象B送给对象A。
IoC容器就是一个对象制造工厂,你需要什么,它会给你送去,你直接使用就行了,而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IoC容器包办。
在传统的实现中,由程序内部代码来控制组件之间的关系。我们经常使用new关键字来实现两个组件之间关系的组合,这种实现方式会造成组件之间耦合。
IoC很好地解决了组件间耦合的问题,它将实现组件间关系从程序内部提到外部容器,也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。
控制反转的实现
IOC关注服务(或应用程序部件)是如何定义的以及他们应该如何定位他们依赖的其它服务。通常,通过一个容器或定位框架来获得定义和定位的分离,容器或定位框架负责:
- 保存可用服务的集合
- 提供一种方式将各种部件与它们依赖的服务绑定在一起
- 为应用程序代码提供一种方式来请求已配置的对象(例如,一个所有依赖都满足的对象), 这种方式可以确保该对象需要的所有相关的服务都可用。
IoC容器的对象实例化是通过xml配置文件来实现的。术语上这叫做注入。注入有两种形式,采用构造方法注入和采用setter注入。
IoC容器实现的bean配置与我们在代码中new实例达到的效果是一样的。
那我们实例化的时候,可以采用单例模式,只保证有一个实例在运行,也可以多个实例运行。
IoC容器中有这种配置吗?
当然有,那就是bean的scope作用域。
singleton默认值,每次调用getBean()向IOC容器中取得的对象是相同的。即单例。
而prototype,则是每次调用getBean()向IOC容器中取得对象是不相同的。即相当于普通的实例化。
<bean id="bean1"class="com.jeiker.spring.Bean1"scope="prototype"/>
或者
<bean id="bean2"class="com.jeiker.spring.Bean2"scope="singleton"/>
通过IoC控制反转,大量减少了Factory和Singleton的数量,使代码层次更加清晰。