评论翻译
这是对这篇文章的翻译,所以如果您是英语使用者,请阅读原文。
这是我第一次正式翻译整篇英文文章,感觉真的比自己写还要累啊...... :(
------------------------------------------------------------------------------------------------------------------
Bert Ertman,Paul Bakker和Luminis写了一系列的文章来介绍如何将应用从Spring迁移到Java EE6上,并且他们还提供了一个简单的实例项目。
在本系列中,Paul和Bert从基本原理开始介绍整个Spring到Java EE6的迁移过程,并通过实际的例子展示了如何升级Web UI显示层,替换数据访问层,如何从AOP切换到CDI拦截器,迁移JMX,如何处理JDBC模板等,另外,还额外演示了如何使用Arquillian对基于Java EE6的应用程序进行集成测试。
简介
在过去的几年中,越来越多的人开始对Java EE感兴趣了,Java EE 5的出现让人耳目一新,Java EE 6则重建了开发人员对Java EE技术体系的信心。现在,Java EE已经成为当下的热点技术,许多开发人员都在重新对其进行评估,并审视自己对其的固有印象。在2003/2004年时,J2EE正处于低谷时期,因为它过于理论化而忽视了如何解决实际问题,让开发人员对J2EE嗤之以鼻。正是在那个时期,一本书横空出世,从本质上改变了之后五年内企业级Java开发的方式。这本书正是《J2EE Design and Development》,不久之后,又有一本《J2EE without EJB》出版,这两本书都出自Rod Johnson(译注:最近Rod Johnson刚刚从SpringSource离开)之手。
开发人员当时非常喜欢这两本书和书中对他们在开发中遇到的问题所给出的解决方案。事实上,开发人员现在仍然很喜欢这些书,但是他们并没有意识到现在的世界和几年前已经发生了根本性的改变。现在,我们需要思考的是那些在Rod Johnson 2003/2004的书中所提出的前提条件是否还合理。按照我们的观点,所有书中所提到的问题,现在都可以使用基于轻量级POJO的Java EE技术解决。所以,如果你仍然在意那两本书,那么表达你敬意最好的方式可能就是用它们垫桌子/显示器啥的。
有两种情况最有可能讨论到究竟是用Spring还是Java EE,从头开发一个全新的企业级应用,或者升级一个遗留的应用。如果是升级一个六七年前的Java应用,那么不管是用Spring还是Java EE,都是一个相当大的麻烦事。不过,如果是一个从头开始的项目,我们认为选择Spring还是Java EE根本就不是一个问题,Java EE由于其是Java业界的标准,并且轻量,对于主流企业级应用开发中的问题都有合适的解决方案,自然是我们应该优先选择的方案。如果没有特殊原因,你不应该选择标准技术之外的东西。
本文并不着重于讨论究竟哪种技术更好,Spring还是Java EE,我们想要展示的是如何解决在升级老的Spring项目的过程中所遇到的问题。并且,我们也不鼓励完全按照本文所讲的路径进行升级。现实中,可能会有各种各样的原因无法完全遵循本文所介绍的迁移步骤进行,例如时间、金钱和经验等因素。不过我们保证,当你遗留的Spring项目遇到问题,并且你想把它迁移到一个现代的企业软件架构,还需要保证这个架构在未来五年内能够满足要求的话,本文将为你演示一个可行的方案。
为什么要迁移?
在我们讨论如何迁移一个遗留的Spring项目之前,首先需要问自己的是“为什么要这样做?”这绝对是一个合理的问题,并且它可以有很多答案。首先,Spring是一个创建于主流技术不能满足大家要求的年代的开源项目,它从诞生以来一直都很成功,所以,它从一开始就吸引了风险投资的眼球,最终,被专注于虚拟化的VMware所收购。对于Java世界的人来说,大家可能都知道可以用它在我们的Mac上运行虚拟机运行Windows。不过,Spring及其众多子项目,没有一个成为Java标准,尽管还是有公司和个人在推动Spring的标准化进程。据我们所知,推动Spring的标准化,无论是对Spring项目还是它身后的SpringSource公司,都没有明显的好处。当然,这些都是公司间的政治,大多数开发人员对此并不感兴趣,所以我们还是从技术的角度来看看为什么迁移到Java EE是一个更好的选择。
从技术角度来看,即使你要把老版本的Spring项目升级到新版,还是有很多工作要做,老版本中所用到的好多Spring技术可能很快或者已经不被支持了。
当我们提到《老版本的Spring项目》时,我们想到的是大量复杂的XML配置文件,过时的DAO层技术,如JDBC Template、Kodo或TopLink,还有像SimpleFormController这样的Web MVC扩展——这已经是过时不再推荐使用的。
现在还有多少程序员精通这些技术?即使有,未来五年内还能保持这种精通吗?根据我们自己的经验,这些老项目每年都需要维护,需要每年更换不同的Web/ORM框架以适应框架在当时的最新版本。所有这些都需要对项目进行大规模的改动,部分程序需要从根本上更新,有时甚至需要从头开始。既然你都能忍受这些,那么为什么不一步到位,直接将项目转换成符合Java EE标准的呢?
谣言终结者
如果你对Java EE是否能够满足你的需求仍然持怀疑态度,那么我们建议你继续阅读本文,希望能够消除你对其的一些误解。大家可能都对J2EE的一些缺点有所了解,但是,一些开发人员就此完全放弃了Java EE,也不再关注其最新进展,因此可能对当前Java EE不是很了解。
本文的目的不是向你全面介绍Java EE6,而是通过对比Spring和Java EE 6中的关键技术来说明为什么我们认为你应该选择Java EE 6。
轻量
过去,大家经常抱怨Java EE的一个问题是它过于沉重,甚至有人把Java EE解释成Java Evil Edition。这个问题现在还存在吗?光听我们说可能还不够,让我们看看现在的应用服务器启动时间。在一台不是很老的PC上,最新版的JBoss AS 7能在2到5秒内完成启动和部署一个完整的Java EE6项目,这基本上和使用Tomcat + Spring相同。不过,如果考虑到你的项目war/ear包的大小,就会有明显的不同。一个标准的Java EE6项目最终的部署文件(war/ear)大约只有100K大小,而Spring则差不多要30M。这是因为对于基于Java EE的项目来说,所有的标准Java EE服务都是由应用服务器提供的,因此不需要再将依赖的jar包打进你自己的项目当中。
我们最喜欢的一个观点来自于JBoss的工程师Andrew Lee Rubinger,他说“没有任何Java EE标准要求应用服务器要笨重并且缓慢”——非常正确!
依赖注入
仅仅从技术角度,我们值得看看过去的J2EE在这方面有哪些不足,而Spring正是从这里切入的。过去,大家选择Spring的一个重要原因是它提供了反转控制(Inversion of Control, IoC),或者现在比较流行的名字,依赖注入(Dependency Injection, DI)。根据维基百科上的表述,反转控制是一种开发模式,核心在于让可重用的结构化代码控制业务逻辑代码。这个模式有一个隐性的前提条件就是结构化代码和业务逻辑代码是分别独立开发的,然后再整合进一个程序当中。反转控制有时也被表述为“好莱坞原则”,即“不要给我打电话,有需要的时候我会叫你”,因为其实现通常依赖于回调函数。
尽管反转控制通常被认为是由Spring框架的作者发明的,但实际上,早在上个世纪八十年代就已经有公开的出版物提到过这个古老的设计模式了。Spring所做的实际上是把这个设计模式成功应用到企业级Java开发中,并借助于此,大幅提高了代码之间的关系解耦,从而得到了更好的可测试代码。Java EE在很长一段时间内都做不到这一点,但是,从Java EE6开始,基于上下文关系的依赖注入(Contextual Dependency Injection, CDI)成为了EE标准的一部分,它提供了强大的基于上下文关系的依赖注入,并且能够非常灵活地注入各种标准规范所提供的服务。如果你还不了解它,那可能真是一种损失了。
面向方面编程
另一项由Spring引领而流行起来的技术就是面向方面编程(Aspect Oriented Programming, AOP)。通过使用AOP,基于面向对象的语言能够在编译期或运行期被织入一些横向关注点。典型的场景就是日志和安全,当然,AOP的能力并不局限于这两部分。但是过度使用AOP则是另一个常见的误区,这会导致代码可读性降低。这是因为AOP所关注的切面,和切面逻辑的实现代码并不在同一个位置。这样,要想知道一段代码在运行时究竟干了哪些事情就不是那么清楚了。当然,这并不是说AOP就一无是处,如果你能够合理地使用AOP的话,它能够帮你很好地做到关注点分离和代码重用。
我们通常把在有限的位置使用AOP称为“轻量级的AOP”,这正是Java EE中拦截器所提供的功能。EJB中过滤器的实现能够在某种程度上达到限制滥用AOP的作用。过滤器模型是在Java EE 5时被引入的,如果把它和CDI(在Java EE 6中被引入)结合起来,可以做到很清晰的关注分离架构,并且大幅减少重复代码。
测试
在上面介绍依赖注入时,我们已经简单提到了这块内容。在过去的J2EE中,基本上很难做到真正的功能代码测试,主要原因是大部分J2EE组件都依赖于各种运行时的服务才能正常工作。这一点是可测试设计的死穴。而现在的Java EE已经回归到基于POJO的组件设计,可测试性提升不少,但各个组件依旧依赖于运行时的服务。为了真正对Java EE组件在应用服务器中进行测试,我们需要创建一个模拟(mock)框架。或者不需要?
正是在不久之前,Arquillian框架横空出世,为Java EE领域中的功能测试创造了可能性。
通过使用Arquillian,我们可以抛开各种模拟框架,直接在容器中对Java EE组件进行测试。在测试被执行之前,Arquillian会先创建一个所谓的微型部署文件(micro deployment),包含了被测试的Java EE组件和它直接依赖的服务,然后由此创建出一个可部署文件并将其部署到一个正在运行的Java EE容器中(或者临时启动一个)。
Arauillian也不会强迫你转向一个新的测试技术,相反,它会无侵入性地与你喜爱的测试框架集成,例如JUnit。在测试领域,Arquillian可以说是Java EE的最佳伴侣。在Arquillian的网站上提供了非常好的文档和大量的示例,同时,在本系列文章中,我们也会向你展示如何编写基本的功能性测试。
工具
最后,我们都有过这样的经历,开发工具过于笨重、缓慢,还得先画一堆UML,再通过复杂的向导一步步往下走,幸运的情况下才能够把向导走完,才能做出个简单的东西来。你的电脑还会像一辆小汽车正在被一个大卡车蹂躏一样地狂叫。幸运的是,这些情况都过去了。现在主流的三大Java IDE都已经对开发Java EE组件有了很好的支持,并且占用资源也不那么多。开发Java EE应用也不再被限定在某一家的工具上了,你可以根据自己的喜好来选择IDE和应用服务器。通过使用诸如JBoss Forge等工具来创建一个基于Maven的Java EE项目现在轻而易举。
Spring和Java EE的功能对比
功能 | Spring | Java EE |
依赖注入 | Spring 容器 | CDI |
事务 | AOP/Annotations | EJB |
Web 框架 | Spring Web MVC | JSF |
AOP | AspectJ (只支持Spring Beans) | 拦截器 |
消息 | JMS | JMS/CDI |
数据访问 | JDBC Template / other ORM / JPA | JPA |
RESTful | Spring Web MVC(3.x) | JAX-RS |
集成测试 | Spring Test Framework | Arquillian |
作为总结,我们可以负责任地说,轻量级的Java EE能够提供Spring所提供的所有功能。
迁移方法
那么,如何开始这个迁移呢?有些人可能会直接放弃遗留项目然后从头开始,尽管这种方式很吸引人,并且如果时间和资金没有限制的话这样做非常可行。不过,对于大多数现实情况来说,这显然不可取。我们需要一种渐进式替换的方法,并且保证在这个过程中不会出现什么灾难性的故障。我们需要一个迁移方案来引导我们一步步向前推进,这个方案不应限制我们的创造性,并且应该允许我们在任何一步时停下来。因此,我们得出以下迁移方案:
- 升级Spring到最新版本
- 替换Spring中使用的过时的框架(例如ORM、Web框架等)
- 同时运行Spring容器和应用服务器
- 完全替换掉Spring
- 移除Spring容器
在本系列的下一篇文章中,我们将重点介绍如何进行迁移,并通过一个真实的示例项目向你展示迁移过程中的不同阶段。届时会有实例代码和一个GitHub上的项目提供给你,这样,你可以自己动手尝试整个迁移过程。
关于作者
作者:Bert Ertman,Paul Bakker
Bert Ertman(@BertErtman)是Luminis公司的院士,该公司位于荷兰,同时还是荷兰Java用户组的领导人(该用户组大约有3500名成员)。
Paul Bakker(@pbakker)是Luminis公司的一名高级工程师,同时也是JBoss Seam、Arquillian和Forge等项目的贡献者。
这两位作者都有着丰富的企业应用软件开发经验,无论是使用J2EE之前的技术,还是J2EE、Spring以及现代的Java EE技术。他们对现代的企业软件开发技术有过很多讨论,包括Spring和Java EE的对比,现在,他们相信,无论是全新的企业应用软件,还是迁移已经被广泛部署的遗留项目,Java EE 6都可以提供最佳的技术。本文的作者们已经在全球很多技术会议上介绍和推荐过Java EE 6技术了,包括J-Fall、Jfokus、Devoxx和JavaOne。本系列文章是基于他们在JavaOne 2011年上广受好评的演讲《迁移Spring到Java EE6的最佳实践》撰写的。