| Introducing to Spring Framework 作者:Rod Johnson 译者:yanger,taowen 校对:taowen 关于Spring Framework,今年夏天你可能已经听见很多的议论。在本文中,我将试图解释Spring能完成什么,和我怎么会认为它能帮助你开发J2EE应用程序。 又来一个framework? 你可能正在想“不过是另外一个的framework”。当已经有许多开放源代码(和专有) J2EE framework时,为什么你还要耐下心子读这篇文章或去下载Spring Framework? 我相信Spring是独特的,有几个原因: 它关注的领域是其他许多流行的Framework未曾关注的。Spring要提供的是一种管理你的业务对象的方法。 Spring既是全面的又是模块化的。Spring有分层的体系结构,这意味着你能选择仅仅使用它任何一个独立的部分,而它的架构又是内部一致。因此你能从你的学习中,得到最大的价值。例如,你可能选择仅仅使用Spring来简单化JDBC的使用,或用来管理所有的业务对象。 它的设计从一开始就是要帮助你编写易于测试的代码。Spring是使用测试驱动开发的工程的理想框架。 Spring不会给你的工程添加对其他的框架依赖。Spring也许称得上是个一站式解决方案,提供了一个典型应用所需要的大部分基础架构。它还涉及到了其他framework没有考虑到的内容。 尽管它仅仅是一个从2003年2月才开始的开源项目,但Spring有深厚的历史根基。这个开源工程是起源自我在2002年晚些时候出版的《Expert One-on-One J2EE设计与开发》书中的基础性代码。这本书展示了Spring背后的基础性架构思想。然而,对这个基础架构的概念可以追溯到2000年的早些时候,并且反映了我为一系列商业工程开发基础结构的成功经验。 2003年1月,Spring已经落户于SourceForge上了。现在有10个开发人员,其中6个是高度投入的积极分子。 Spring架构上的好处 在我们进入细节之前,让我们来看看Spring能够给工程带来的种种好处: Spring能有效地组织你的中间层对象,不管你是否选择使用了EJB。如果你仅仅使用了Struts或其他为J2EE的 API特制的framework,Spring致力于解决剩下的问题。 Spring能消除在许多工程中常见的对Singleton的过多使用。根据我的经验,这是一个很大的问题,它降低了系统的可测试性和面向对象的程度。 通过一种在不同应用程序和项目间一致的方法来处理配置文件,Spring能消除各种各样自定义格式的属性文件的需要。曾经对某个类要寻找的是哪个魔法般的属性项或系统属性感到不解,为此不得不去读Javadoc甚至源编码?有了Spring,你仅仅需要看看类的JavaBean属性。Inversion of Control的使用(在下面讨论)帮助完成了这种简化。 通过把对接口编程而不是对类编程的代价几乎减少到没有,Spring能够促进养成好的编程习惯。 Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。 使用Spring构建的应用程序易于单元测试。 Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。 Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物,它们适用于许多web应用。例如,Spring能使用AOP提供声明性事务管理而不通过EJB容器,如果你仅仅需要与单个数据库打交道,甚至不需要一个JTA实现。 Spring为数据存取提供了一个一致的框架,不论是使用的是JDBC还是O/R mapping产品(如Hibernate)。 Spring确实使你能通过最简单可行的解决办法来解决你的问题。而这是有有很大价值的。 Spring做了些什么? Spring提供许多功能,在此我将依次快速地展示其各个主要方面。 任务描述 首先,让我们明确Spring范围。尽管Spring覆盖了许多方面,但我们对它应该涉什么,什么不应该涉及有清楚的认识。 Spring的主要目的是使J2EE易用和促进好编程习惯。 Spring不重新轮子。因此,你发现在Spring中没有logging,没有连接池,没有分布式事务调度。所有这些东西均有开源项目提供(例如我们用于处理所有日志输出的Commons Logging以及Commons DBCP),或由你的应用程序服务器提供了。出于同样的的原因,我们没有提供O/R mapping层。对于这个问题已经有了像Hibernate和JDO这样的优秀解决方案。 Spring的目标就是让已有的技术更加易用。例如,尽管我们没有底层事务协调处理,但我们提供了一个抽象层覆盖了JTA或任何其他的事务策略。 Spring没有直接和其他的开源项目竞争,除非我们感到我们能提供新的一些东西。例如,象许多开发人员一样,我们从来没有对Struts感到高兴过,并且觉得到在MVC web framework中还有改进的余地。在某些领域,例如轻量级的IoC容器和AOP框架,Spring确实有直接的竞争,但是在这些领域还没有已经较为流行的解决方案。(Spring在这些领域是开路先锋。) Spring也得益于内在的一致性。所有的开发者都在唱同样的的赞歌,基础想法依然与Expert One-on-One J2EE设计与开发中提出的差不多。 并且我们已经能够在多个领域中使用一些中心的概念,例如Inversion of Control。 Spring在应用服务器之间是可移植的。当然保证可移植性总是一种挑战,但是我们避免使用任何平台特有或非标准的东西,并且支持在WebLogic,Tomcat,Resin,JBoss,WebSphere和其他的应用服务器上的用户。 Inversion of Control 容器 Spring设计的核心是 org.springframework.beans 包, 它是为与JavaBeans一起工作而设计的。 这个包一般不直接被用户使用,而是作为许多其他功能的基础。 下一个层面高一些的抽象是"Bean Factory"。一个Spring bean factory 是一个通用的Factory,它使对象能够按名称获取,并且能管理对象之间的关系。 Bean factories 支持两种模式的对象: Singleton:在此模式中,有一个具有特定名称的共享对象实例,它在查找时被获取。这是默认的,而且是最为经常使用的。它对于无状态对象是一种理想的模式。 Prototype:在此模式中,每次获取将创建一个独立的对象。例如,这可以被用于让用户拥有他们自己的对象。 由于 org.springframwork.beans.factory.BeanFactory是一个简单的接口,它能被大量底层存储方法实现。你能够方便地实现你自己的BeanFactory,尽管很少用户需要这么做。最为常用的BeanFactory定义是: XmlBeanFactory: 可解析简单直观的定义类和命名对象属性的XML结构。 我们提供了一个DTD来使编写更容易。 ListableBeanFactoryImpl:提供了解析存放在属性文件中的bean定义的能力,并且可通过编程创建BeanFactories。 每个bean定义可能是一个POJO(通过类名和JavaBean初始属性定义),或是一个FactoryBean。FactoryBean接口添加了一个间接层。通常,这用于创建使用AOP或其他方法的代理对象:例如,添加声明性事务管理的代理。(这在概念上和EJB的interception相似,但实现得更简单。) BeanFactories能在一个层次结构中选择性地参与,继承ancestor(祖先)的定义。这使得在整个应用中公共配置的共享成为可能,虽然个别资源,如controller servlets,还拥有他们自己的独立的对象集合。 这种使用JavaBeans的动机在《Expert One-on-One J2EE Design and Development》的第四章中有描述,在TheServerSide网站上的有免费的PDF版本(http://www.theserverside.com/resources/article.jsp?l=RodJohnsonInterview)。 通过BeanFactory概念,Spring成为一个Inversion of Control的容器。(我不怎么喜欢container这个词,因为它使人联想到重量级容器,如EJB容器。Spring的BeanFactory是一个可通过一行代码创建的容器,并且不需要特殊的部署步骤。) Inversion of Control背后的概念经常表述为Hollywood原则的:“Don’t call me, I’ll call you。” IoC将控制创建的职责搬进了框架中,并把它从应用代码脱离开来。涉及到配置的地方,意思是说在传统的容器体系结构中,如EJB,一个组件可以调用容器并问“我需要它给我做工作的对象X在哪里?”;使用IoC容器则只需指出组件需要X对象,在运行时容器会提供给它。容器是通过查看方法的参数表(例如JavaBean的属性)做到的,也可能根据配置数据如XML。 IoC有几个重要的好处,例如: 因为组件不需要在运行时间寻找合作者,所以他们可以更简单的编写和维护。在Spring版的IoC里,组件通过暴露JavaBean的setter方法表达他们依赖的其他组件。这相当于EJB通过JNDI来查找,EJB查找需要开发人员编写代码。 同样原因,应用代码更容易测试。JavaBean属性是简单的,属于Java核心的,并且是容易测试的:仅编写一个自包含的Junit测试方法用来创建对象和设置相关属性即可。 一个好的IoC实现保留了强类型。如果你需要使用一个通用的factory来寻找合作者,你必须通过类型转换将返回结果转变为想要的类型。这不是一个大不了的问题,但是不雅观。使用IoC,你在你的代码中表达了强类型依赖,框架将负责类型转换。这意味着在框架配置应用时,类型不匹配将导致错误;在你的代码中,你无需担心类型转换异常。 大部分业务对象不依赖于IoC容器的APIs。这使得很容易使用遗留下来的代码,且很容易的使用对象无论在容器内或不在容器内。例如,Spring用户经常配置Jakarta Commons DBCP数据源为一个Spring bean:不需要些任何定制代码去做这件事。我们说一个IoC容器不是侵入性的:使用它并不会使你的代码依赖于它的APIs。任何JavaBean在Spring bean factory中都能成为一个组件。 最后应该强调的是,IoC 不同于传统的容器的体系结构,如EJB,应用代码最小程度地依靠于容器。这意味着你的业务对象可以潜在的被运行在不同的IoC 框架上——或者在任何框架之外——不需要任何代码的改动。 以我和其他Spring用户的经验来说,再怎么强调IoC给应用程序代码带来的好处也不为过。 IoC不是一个新概念,但是它在J2EE团体里面刚刚到达黄金时间。 有一些可供选择的IoC 容器: 例如 Apache Avalon, PicoContainer 和 HiveMind。Avalon 从没怎么流行,尽管它很强大而且有很长的历史。Avalon相当的重和复杂,并且看起来比新的IoC解决方案更具侵入性。 PicoContainer是一个轻量级而且更强调通过构造函数表达依赖性而不是JavaBean 属性。 与Spring不同,它的设计允许每个类型一个对象的定义(可能是因为它拒绝任何Java代码外的元数据导致的局限性)。在Spring, PicoContainer 和其他 IoC frameworks之间做比较,可参看文章Spring网站上的"The Spring Framework - A Lightweight Container"位于http://www.springframework.org/docs/lightweight_container.html。这个页面里面包含了PicoContainer站点的链接 。 Spring BeanFactories 是非常轻量级的。用户已经成功地将他们应用在applets和单独的Swing应用中。(它们也很好地工作在EJB容器中。) 没有特殊的部署步骤和察觉得到的启动时间。这个能力表明一个容器在应用的任何层面几乎立即可以发挥非常大的价值。 Spring BeanFactory 概念贯穿于Spring始终, 而且是Spring如此内在一致的关键原因。在IoC容器中,Spring也是唯一的,它使用IoC作为基础概念贯穿于整个功能丰富的框架。 对应用开发人员,最重要的是,一个或多个BeanFactory提供了一个定义明确的业务对象层。这类似于local session bean层,但比它更简单。与EJBs不同,在这个层中的对象可能是相关的,并且他们的关系被拥有它们的factory管理。有一个定义明确的业务对象层对于成功的体系结构是非常重要的。 Spring ApplicationContext 是BeanFactory的子接口,为下列东西提供支持: 信息查找,支持着国际化 事件机制,允许发布应用对象以及可选的注册以接收到事件 可移植的文件和资源访问 XmlBeanFactory 例子 Spring用户通常在XML的“bean定义”文件中配置他们的应用。Spring的XML bean定义文档的根是<beans> 元素。该元素包含一个或多个 <bean>定义。我们一般给每个bean定义的指定类和属性。我们还必须指定ID作为标识,这将成为在代码中使用该bean的名字。 让我们来看一个简单的例子,它配置了三个应用程序对象,之间的关系在J2EE应用中常常能够看到: J2EE DataSource 使用DataSource的DAO 在处理过程中使用DAO的业务对象 在下面的例子中,我们使用一个来自Jakarta Commons DBCP项目的BasicDataSource。这个class(和其他许多已有的class一样)可以简单地被应用在Spring bean factory中,只要它提供了JavaBean格式的配置。需要在shutdown时被调用的Close方法可通过Spring的"destroy-method"属性被注册,以避免BasicDataSource需要实现任何Spring 的接口。 代码: <beans> <bean /></property> </bean> 在幕后有许多魔法般的事情发生,Spring AOP framework的殷勤,虽然不强迫你使用AOP的概念享受这些结果。“myComponent”bean定义为EJB创建一个代理,它实现了业务方法的接口。EJB local home在启动的时候被缓存,因而只需要一次JNDI查找。每次EJB被调用的时候,代理调用local EJB中的create()方法并且调用EJB中对应的业务方法。 myController bean定义为这个代理设置controller类的myController属性。 这个EJB访问机制极大简化了应用程序的代码: Web层的代码不依赖于EJB的使用。如果你想要使用POJO,mock object或者其他test stub替代EJB引用,我们可以简单地改动一下myComponent bean定义而不影响一行Java代码 我们还不需要写一行JNDI查找或者其他EJB plumbing code。 在实际程序中的性能测试和经验标明这种方法(包括对目标EJB的反射调用)的性能影响是很小的,在典型的应用中检测不出。记住无论如何我们都不希望使用fine-grained的EJB调用,因为会有有关应用服务器上的EJB的底层架构方面的代价。 我们可以把相同方法应用于远程EJB,通过类似org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean factory bean的方法。然而我们无法隐藏远程EJB的业务方法接口中的RemoteException。 测试 如你可能已经注意到的,我和其他Spring开发这是全面单元测试重要性的坚定支持者。我们相信框架被彻底单元测试过的是非常重要的,而且我们框架设计的主要目标是让建立在框架之上的程序易于单元测试。 Spring自身有一个极好的单元测试包。我们的1.0 M1的单元测试覆盖率是75%,而且我们希望在1.0 RC1的时候能够达到80%的单元测试覆盖率。我们发现在这个项目中测试优先的开发带来的好处是实实在在的。例如,它使得作为国际化分布式开发团队的工作极端有效率,而且用户评论CVS snapshots趋向于稳定和使用安全。 因为以下理由,我们相信用Spring构建的应用程序是非常易于测试的: IoC推动了单元测试 应用程序不包括直接使用注入JNDI的J2EE服务的plumbing code,这些代码一般让测试难于进行 Spring bean factories和contexts能够在容器外设置 在容器外可以设置Spring bean factory的能力提供了对开发过程有趣的可选项。在几个使用Spring的web应用中,工作是从定义业务接口和在web容器外集成测试开始的。在业务功能已经足够完整之后,web接口不过是添加在其上的薄薄一层。 谁在使用Spring 虽然相对来说Spring还是一个新的项目,但是我们已经有了一个令人印象深刻并且不断增长的用户群。它们已经有许多产品使用着Spring。用户包括一个主要的全球投资银行(做大型项目的),一些知名的网络公司,几个web开发顾问机构,卫生保健公司,以及学院机构。 许多用户完整地使用Spring,但是一些只单独使用一些组件。例如,大量用户使用我们地JDBC或者其他数据访问功能。 Roadmap 在今年晚些时候我们主要要做的是让Spring发布release 1.0。然而,我们还有一些更长远的目标。 为1.0 final规划地主要改进式源代码级地元数据支持,它主要用于(但不局限于)AOP框架。这将使得C#风格的attribute驱动的事务管理,并且让声明式企业服务在典型应用情况下非常容易配置。Attribute支持将会在Spring的1.0 final release支持中加入,并且设计的是在发布的那个时候能与JSR-175集成。 1.0之后,一些可能的改进地方包括: 通过对我们的JDBC和事务支持的一个相当抽象来支持JMS 支持bean factories的动态重配置 提供web services的能力 IDE和其他工具支持 作为一个敏捷项目,我们主要是受到用户需求的驱动。因而我们不会开发没有一个用户需要的特性,并且我们会仔细倾听来自用户群的声音。 总结 Spring是一个解决了许多在J2EE开发中常见的问题的强大框架。 Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯。Spring的架构基础是基于使用JavaBean属性的Inversion of Control容器。然而,这仅仅是完整图景中的一部分:Spring在使用IoC容器作为构建完关注所有架构层的完整解决方案方面是独一无二的。 Spring提供了唯一的数据访问抽象,包括简单和有效率的JDBC框架,极大的改进了效率并且减少了可能的错误。Spring的数据访问架构还集成了Hibernate和其他O/R mapping解决方案。 Spring还提供了唯一的事务管理抽象,它能够在各种底层事务管理技术,例如JTA或者JDBC纸上提供一个一致的编程模型。 Spring提供了一个用标准Java语言编写的AOP框架,它给POJOs提供了声明式的事务管理和其他企业事务——如果你需要——还能实现你自己的aspects。这个框架足够强大,使得应用程序能够抛开EJB的复杂性,同时享受着和传统EJB相关的关键服务。 Spring还提供了可以和总体的IoC容器集成的强大而灵活的MVC web框架。 更多信息 参见以下资源获得关于Spring的更多信息: Expert One-on-One J2EE Design and Development(Rod Johnson,Wrox,2002)。虽然Spring在书出版之后已经极大地进步和改进了,它仍然是理解Spring动机的极佳途径。 Spring的主页:http://www.springframework.org。这里包括Javadoc和几个教程。 在Sourceforge上的论坛和下载 Spring用户和Spring开发者的邮件列表 我们正在尽我们可能去改进Spring的文档和示例。我们还为在信件和邮件列表中极好的回复率自豪。我们希望你能快速融入我们的社区! 关于作者 Rod Johnson 作为Java开发者和架构师已经有了7年的经验了并且在J2EE平台出现之初就在其上进行开发了。他是《Expert One-on-One J2EE Design and Development》(Wrox,2002)的作者并且贡献了其他好几本关于J2EE的书。他当前正在为Wiley撰写另外一本有关J2EE架构的书。Rod在两个Java标准委员会服务并且经常师大会发言人。现在他在UK做一个咨询顾问。 |
相关文章: