Ruby on Rails与轻量级J2EE架构Struts+Hibernate之比较分析
2009-02-25
作者:吴吉义,龚祥国
目前,Ruby on Rails正在成为Web应用程序开发的新途径。Ruby on Rails是基于Ruby语言的轻型Web开发架构,不仅开发效率高(部署容易)、功能丰富(支持Ajax等最新应用),而且性能方面表现相当出色。该架构的支持者们声称Ruby on Rails开发人员的生产率最多是使用传统J2EE架构的10倍。也有测试资料显示,该架构性能比轻量级J2EE架构Struts+Hibernate还高15%-30%。
二、两种架构的关键特性
2.1 Ruby on Rails 架构
Ruby是一种解释型面向对象脚本语言,由日本的Yukihiro Matsumoto在1993年2月24日首次发布。Ruby从Perl,Eiffel等语言中吸收了很多特性,使之很适合用于文本文件处理和进行系统管理任务,并且完全面向对象。它的语法简单明快,可扩展并且可以跨平台。Ruby是完全自由开放的,不仅可以免费得到,而且可以自由地使用、复制、修改和分发它。
Ruby on Rails是用Ruby编写的一款完整的、开放源代码Web架构,目的是使用更简单而且更少的代码开发实际使用的应用程序。作为一个完整的框架,Ruby on Rails中的所有的层都是为协同工作而构造的,可以完全只使用一门单一的语言。在Rails中,所有内容(从模板到控制流再到业务逻辑)都是用Ruby编写的。Rails支持基于配置文件和注释的反射(reflection)和运行时扩展。
Ruby on Rails是一种MVC架构,虽然该技术不是Rails所特有的——甚至不是Web应用程序所特有的(相对于其他程序),但是Rails具有非常清晰而专一的MVC思维方式。
⑴模型
Rails应用程序的模型部分主要是其所使用的底层数据库,很多情形下是以一种受管理的方式对关系型数据库管理系统(RDBMS)中的数据执行操作的。
ActiveRecord类是Rails的一个核心组成部分,它将关系型表映射为Ruby对象,使其成为控制器可以操作并能在视图中显示的数据。Rails应用程序可以支持ORACLE、DB2、MySQL等关系数据库。
⑵控制器
控制器以其抽象形式执行应用程序的逻辑。Rails应用程序的app/controllers/目录中的Ruby脚本能把模型数据导入为变量,保存回去或对其进行修改和处理。不过,控制器不关心用户如何适当地显示或者输入数据。Rails仅局限于在Web页中提供和收集数据,但开发人员可以修改Web页的布局——颜色、字体、表格、样式表单等等,与控制器代码无关。
⑶视图
Rails视图是用于编写Ruby代码的界面,包含有用于.rhtml的非常好的模板语言,它将纯粹的HTML与嵌入的Ruby代码组合起来。Rails应用程序界面的最表层外观通常是由CSS样式表单控制的。.rhtml格式是一种增强的HTML,一个简单的HTML文件本身也是一个合法的RHTML模板,但要考虑RHTML提供的脚本控制。
此外,Rails提供了一组代码生成器工具,以替代使用严格的工作空间和IDE的开发环境。简单的应用程序可能完全不需要编码,让Rails在运行时动态地生成客户机HTML页面。第一遍生成代码时创建的只是粗略的支架,然后可以生成更详细的能够定制的控制器、视图和模型。
2.2 轻量级J2EE架构Struts+Hibernate
2.2.1 Struts简介
Struts是MVC设计模式的一种实现,它将Servlet和JSP标记(属于J2EE规范)用作实现的一部分。Struts继承了MVC的各项特性,并根据J2EE的特点,做了相应的变化与扩展。Struts的体系结构如图1所示:
图1 Struts体系结构
Struts是Apache组织中开源项目之一,主要用于实现Web项目中表示层。Struts的核心是ActionSevlet,ActionServlet是一个通用的控制组件,承担MVC中Controller的角色,其核心是Struts-config.xml。在Struts中,用户的请求一般以*.do作为请求服务名,所有的*.do请求均被指向ActionSevlet,ActionSevlet根据Struts-config.xml中的配置信息,将用户请求封装成一个指定名称的FormBean,并将此FormBean传至指定名称的ActionBean,由ActionBean完成相应的业务操作,如文件操作,数据库操作等。每一个*.do均有对应的FormBean名称和ActionBean名称,这些在Struts-config.xml中配置。
2.2.2 Hibernate简介
Hibernate是一种新的ORM映射工具,它不仅提供了从Java类到数据表之间的映射,也提供了数据查询和恢复机制。相对于使用JDBC和SQL来手工操作数据库,使用Hibernate,可以大大减少操作数据库的工作量。
Hibernate可以和多种Web服务器或者应用服务器良好集成,如今已经支持几乎所有的流行的数据库服务器(达16种)。图2显示了Hibernate如何使用数据库和配置文件数据库来为应用程序提供持久服务和持久化对象。
Hibernate的接口大致可以分为以下几种类型:
●一些被用户的应用程序调用的,用来完成基本的创建、读取、更新、删除操作以及查询操作的接口。这些接口是Hibernate实现用户程序的商业逻辑的主要接口,它们包括Session、Transaction和Query。
●Hibernate用来读取诸如映射表这类配置文件的接口,典型的代表有Configuration类。
●回调(Callback)接口。它允许应用程序能对一些事件的发生作出相应的操作,例如Interceptor、Lifecycle和Validatable都是这一类接口。
●一些可以用来扩展Hibernate的映射机制的接口,例如UserType、CompositeUserType和IdentifierGenerator。这些接口可由用户程序来实现(如果有必要)。
图2 Hibernate体系结构
Hibernate使用了J2EE架构中JDBC、JTA、JNDI等技术。其中JDBC是一个支持关系数据库操作的一个基础层;它与JNDI和JTA一起结合,使得Hibernate可以方便地集成到J2EE应用服务器中去。
三、Ruby on Rails与Struts+Hibernate之比较分析
Ruby on Rails堆栈与轻量级J2EE 架构Struts+Hibernate堆栈之间的基本区别很小,两者都有用来执行应用程序代码的容器,都有帮助分离应用程序的模型、视图和控件的MVC框架,以及持久存储数据的机制。图3是对两种架构堆栈的比较。
3.1前端控制器
Ruby on Rails的DispatchServlet和Struts的ActionServlet都是前端控制器模式的例子,它们提供了相同的功能。它们接受HTTP请求并解析URL,把请求的处理转发给适当的动作。在Rails中,动作是扩展自ActionController的类;Struts中,动作是扩展自Action的类。两个前端控制器之间的主要区别是它们如何决定处理具体请求的动作。
图3 Ruby on Rails与Struts+Hibernate堆栈的比较
Rails根据请求的URL发现适当的动作。图4显示,URL http://localhost/order/delete/4告诉Rails调用OrderController实例上的delete方法,并将4作为可用的实例变量。Rails知道/order将映射到文件order_controller.rb中定义的一个控制器类。如果在控制器中定义了find方法,那么只要用find替代URL中的delete,就可以调用这个方法。
图4 Rails和Struts中的URL映射
Struts采用了不同的方式,开发人员需要把特定请求的映射外部化到XML配置文件中的Action类。当首次装入ActionServlet时,它将解析这个文件,并准备接受请求。根据约定,以.do结束的请求被重定向到ActionServlet,由ActionServlet分派到适当的Action。图4的XML是一个典型的映射,它告诉ActionServlet把叫作deleteOrder.do的请求转发到controllers.order.DeleteOrderAction作进一步处理。
3.2动作和模型
在Rails和Struts中,动作用来充当前端控制器和模型之间的桥梁。开发人员提供动作的现实,从而提供特定于应用程序的请求处理。前端控制器负责接受请求,并把请求传递到特定动作。图5显示了Rails和Struts基本的动作层次结构。
在Rails中,必须扩展ActionController::Base,让模型参与到请求处理中。Rails没有将ActionController的实例池化;相反,它为每个请求创建新的实例。虽然这对性能可能有负面影响,但是它可以让开发变得更容易。开发人员不需要关注Struts中存在的线程问题,因此,会话、请求、标题和参数都可以作为ActionController的实例成员来进行访问。
Struts要求开发人员扩展Action并覆盖execute(),以处理请求。通常,每个Action类都提供了非常具体的工作单元。图5显示了三个特定动作:SaveOrderAction、DeleteOrderAction和ListOrdersAction。前端控制器将调用execute()方法,传递给它许多有用的对象,其中包括HTTP请求和响应对象。ActionForm是一个类,可以方便地向视图来回传输并验证与表单有关的输入,ActionMapping包含映射的配置信息,就像图4的XML所描述的那样。execute()方法返回ActionForward对象,Struts用这个对象来确定对请求继续进行处理的组件。
图5 Rails和Struts的动作层次结构
3.3持久性框架
持久性框架用于在应用程序层和数据库之间交换数据。Rails和Hibernate的持久性框架都可以归类为对象/关系映射(ORM)工具,它们接受数据的对象视图,并将该视图映射到关系数据库内的表中。使用两种框架的目的都是为了减少与关系数据库有关的开发时间。但是,图6显示了两者在设计和配置上的一些区别。
图6 ActiveRecord和Hibernate持久性框架的比较
Rails 的 ORM 框架叫作 Active Record,它基于同名的设计模式。Active Record 是包装数据库表或视图中数据行的对象,封装数据库访问,在数据上添加域逻辑。在 Rails 中,每个域对象都将扩展提供 CRUD 操作的 ActiveRecord::Base。Active Record 不需要映射文件;实际上,使用 Active Record 的开发人员不需要对 getter 或 setter、甚至类的属性进行编码。通过一些漂亮的词汇分析,Active Record 能够判断出,Order 类将映射到数据库中的 ORDERS 表。使用 Ruby 反射和元编程的组合,表的列可以变成对象的属性。访问器和调整器也添加了进来。
图7 order.rb
图7显示了 Order 类的完成后的代码。在 Order 类体中有一行代码定义了它与 Item 对象的关系。has_many 是一个静态方法调用,符号 :items 是它的参数。ActiveRecord 用 :items 发现 Item 域对象,然后将这个 Item 对象映射回数据库中的 ITEMS 表。
Hibernate基于DataMapper模式,在这种模式中,特定的映射器类Session负责在数据库中持久存储和检索数据。Hibernate可以持久存储任何Java对象,只要这个对象符合JavaBean规范。XML映射文件描述了如何将类映射到数据库中具体的表,并描述了类与其他类的关系。
图8显示了Hibernate映射文件的一个实例。class标签把Order对象映射到ORDERS表,还有许多子标签用于描述其属性、ID订单名称,以及同models.Item的一对多关系。
图8 Order.hbm.xml
四、结束语
Ruby on Rails提供了开发Web 应用程序的一种极其快捷的途径,正在和已经引起业界相当的兴趣。它更倾向于清楚的代码而不是配置文件,而Ruby语言的动态性质在运行时生成了大部分管道代码。大多数Rails框架都是作为独立项目创建的,而且应用程序开发能够从一组同类组件受益。相比之下,典型的J2EE架构倾向于构建在通常独立开发的最好的组件之上,一般使用XML进行配置并将组件组合在一起。
参考文献:
[1]吴吉义.基于Struts+Hibernate+Spring的电子政务应用系统架构[J].电子政务,2005,(12):32-38.
[2]Rod Johnson.EXPERT ONE-ON-ONE J2EE DEVELOPMENT WITHOUT EJB[M].北京:电子工业出版社,2005.
[3]DAVE THOMAS, CHAD FOWLER, ANDY HUNT.PROGRAMMING RUBY: THE PRAGMATIC PROGRAMMERS' GUIDE[M].北京:电子工业出版社,2006.
[4]JAMES TURNER,KEVIN BEDELL.STRUTS KICK START[M].北京:电子工业出版社,2004.
[5]Aaron Rustad.Ruby on Rails and J2EE: Is there room for both?[EB/OL].
http://www-128.ibm.com/developerworks/web/library/wa-rubyonrails/, 2006-06-01/2006-07-15.
[6]David Mertz.Fast-track your Web apps with Ruby on Rails[EB/OL].
http://www-128.ibm.com/developerworks/linux/library/l-rubyrails/, 2006-06-01/2006-07-15.