Ruby on Rails 和 J2EE:兩者能否共存?
兩個 Web 應(yīng)用程序框架的比較
級別: 高級 |
技術(shù)架構(gòu)師, Anassina, Inc.
2005 年 8 月 11 日
Ruby on Rails 是一個相對較新的 Web 應(yīng)用程序框架,構(gòu)建在 Ruby 語言之上。它被宣傳為現(xiàn)有企業(yè)框架的一個替代,而它的目標,簡而言之,就是讓生活,至少是 Web 開發(fā)方面的生活,變得更輕松。在本文中,Aaron Rustad 將對 Rails 和傳統(tǒng)的 J2EE 框架在架構(gòu)上的一些關(guān)鍵特性進行比較。
Ruby on Rails 是一個 Web 應(yīng)用程序框架,它的目標是為應(yīng)用程序開發(fā)提供一條易行道。實際上,框架的支持者們聲稱 Ruby on Rails 開發(fā)人員的生產(chǎn)率最多是使用傳統(tǒng) J2EE 框架的 10 倍。(請閱讀“Rolling with Ruby on Rails”一文,以獲得關(guān)于這一聲明的更多內(nèi)容;請參閱 參考資料)。雖然這句話造成了 Rails 和 J2EE 社區(qū)相當大的爭議,但爭論中卻很少談及如何比較 Rails 和 J2EE 架構(gòu)。本文將使用企業(yè)應(yīng)用程序中常見的開源工具,對 Rails 框架和典型的 J2EE 實現(xiàn)進行比較。
什么是 Ruby on Rails?
要想找到用一句話描述 Rails 的簡單說明,只需查看項目的 主頁 即可:
Rails 是一個用 Ruby 編寫的全棧的(full-stack)、開源的 Web 框架,可以使用它來輕松編寫實際的應(yīng)用程序,所需的代碼也要比大多數(shù)框架花在處理 XML 上的代碼少。
雖然我不能保證框架確實會提供它所承諾的輕松快樂,但是上面這句話確實很好地總結(jié)了 Rails 的品質(zhì)。全棧包括:Web 服務(wù)器、處理 HTTP 請求和響應(yīng)的框架,以及方便地把數(shù)據(jù)持久存儲到關(guān)系數(shù)據(jù)庫的框架。Rails 通過消除復(fù)雜的 XML 配置文件,使用 Ruby 語言的動態(tài)性質(zhì),幫助把靜態(tài)類型語言中常見的許多重復(fù)代碼減少到最少,努力使開發(fā)工作變得更容易。
Rails 和典型的 J2EE Web 堆棧
圖 1 比較了 Rails 堆棧和典型的 J2EE Web 堆棧(包括 Tomcat servlet 容器、Struts Web 應(yīng)用程序框架和 Hibernate 持久性框架)。
可以看到,Rails 堆棧和構(gòu)成普通的基于 J2EE 的 Web 應(yīng)用程序的組件之間的基本區(qū)別很小。兩者都有用來執(zhí)行應(yīng)用程序代碼的容器;都有幫助分離應(yīng)用程序的模型、視圖和控件的 MVC 框架;以及持久存儲數(shù)據(jù)的機制。
MVC 框架 |
前端控制器
Struts 的 ActionServlet
和 Rails 的 DispatchServlet
都是前端控制器模式的例子;所以,它們提供了相同的功能。它們接受 HTTP 請求,解析 URL,把請求的處理轉(zhuǎn)發(fā)給適當?shù)膭幼鳌T?Struts 中,動作是擴展自 Action
的類;對于 Rails,動作是擴展自 ActionController
的類。兩個前端控制器之間的主要區(qū)別是它們?nèi)绾螞Q定處理具體請求的動作。
使用 Struts,開發(fā)人員需要把特定請求的映射外部化到 XML 配置文件中的 Action
類。當首次裝入 ActionServlet
時,它將解析這個文件,并準備接受請求。根據(jù)約定,以 .do
結(jié)束的請求被重定向到 ActionServlet
,由 ActionServlet 分派到適當?shù)?Action
。圖 2 的 XML 是一個典型的映射。它告訴 ActionServlet
把叫作 deleteOrder.do
的請求轉(zhuǎn)發(fā)到 controllers.order.DeleteOrderAction
作進一步處理。
Rails 采用了不同的方式。它沒有依賴配置文件把請求映射到某一個動作,而是根據(jù)請求的 URL 發(fā)現(xiàn)適當?shù)膭幼鳌膱D 2 可以看到,URL http://localhost/order/delete/4
告訴 Rails 調(diào)用 OrderController
實例上的 delete
方法,并將 4
作為可用的實例變量。Rails 足夠聰明,知道 /order
將映射到文件 order_controller.rb 中定義的一個控制器類。如果在控制器中定義了 find
方法,那么只要用 find
替代 URL 中的 delete
,就可以調(diào)用這個方法。
動作和模型
在 Rails 和 Struts 中,動作用來充當前端控制器和模型之間的橋梁。開發(fā)人員提供動作的現(xiàn)實,從而提供特定于應(yīng)用程序的請求處理。前端控制器負責接受請求,并把請求傳遞到特定動作。圖 3 演示了 Rails 和 Struts 基本的動作層次結(jié)構(gòu)。
圖 3. Rails 和 Struts 的動作層次結(jié)構(gòu)
動作是模型還是控制器? |
Struts 要求開發(fā)人員擴展 Action
并覆蓋 execute()
,以處理請求。通常,每個 Action
類都提供了非常具體的工作單元。圖 3 演示了三個特定動作:SaveOrderAction
、DeleteOrderAction
和 ListOrdersAction
。前端控制器將調(diào)用 execute()
方法,傳遞給它許多有用的對象,其中包括 HTTP 請求和響應(yīng)對象。ActionForm
是一個類,它可以方便地向視圖來回傳輸并驗證與表單有關(guān)的輸入,ActionMapping
包含映射的配置信息,就像 圖 2 的 XML 所描述的那樣。
execute()
方法返回 ActionForward
對象,Struts 用這個對象來確定對請求繼續(xù)進行處理的組件。一般來說,這個組件是一個 JSP 頁面,但是 ActionForward
也能指向其他動作。開發(fā)人員必須清楚,Struts 創(chuàng)建的是 Action
的單一實例,并允許多個線程調(diào)用它的 execute()
。這使請求處理變得更快,因為框架處理每個請求時不用頻繁地創(chuàng)建新的 Action
實例。但是因為可以在多個線程之間共享單一對象,所以必須遵守適當?shù)木€程注意事項,因為其他線程可能會破壞在這個動作中保持狀態(tài)的實例變量。
在 Rails 中,必須擴展 ActionController::Base
,讓模型參與到請求處理中。Rails 沒有將 ActionController
的實例池化;相反,它為每個請求創(chuàng)建新的實例。雖然這對性能可能有負面影響,但是它可以讓開發(fā)變得更容易。開發(fā)人員不需要關(guān)注 Struts 中存在的線程問題,因此,會話、請求、標題和參數(shù)都可以作為 ActionController
的實例成員來進行訪問。ActionController
還是一個將特定域邏輯的所有處理組合在一起的合理場所。Struts 的 Action
類是細粒度的,它提供了非常具體的工作單元,而 Rails ActionController
則是粗粒度的,它將具體的工作單元模擬為一些方法。
清單 1 和 清單 2 分別演示了典型的 Struts 動作和典型的 Rails 動作
表 1 提供了對兩種方法的邏輯流程的比較,并演示了清單 1 和清單 2 的特定行中發(fā)生的事情。研究 DeleteOrderAction
的 execute()
方法和 OrderController
的 delete
方法,可以看出它們基本上是相同的。
步驟 | Struts | Rails |
框架調(diào)用動作 | 行 03: execute() |
行 07: delete |
從請求中檢索到的 ID | 行 06-07:從請求對象中取出 | 行 08:從所有參數(shù)的實例哈希中取出 |
從數(shù)據(jù)庫刪除訂單記錄 | 行 09、14-24:調(diào)用 delete() 方法,用 Hibernate 刪除記錄 |
行 09:用 ActiveRecord 刪除記錄 |
重定向到列出剩余訂單 | 行 11:用 ActionMapping 對象查找將要轉(zhuǎn)發(fā)處理的下一個組件。圖 2 中的 XML 映射顯示,success 將映射到 /listOrders ,這是另一個 Action ,負責查找剩余訂單,并以 JSP 的形式呈現(xiàn)它們 |
行 10:用將調(diào)用的下一動作的哈希來調(diào)用 redirect_to 方法;在這種情況下,它只是調(diào)用同一控制器的 list 方法 |
持久性框架
持久性框架 用來在應(yīng)用程序?qū)雍蛿?shù)據(jù)庫之間來回移動數(shù)據(jù)。Hibernate 和 Rails 的持久性框架可以歸類為對象/關(guān)系映射(ORM)工具,這意味著它們接受數(shù)據(jù)的對象視圖,并將該視圖映射到關(guān)系數(shù)據(jù)庫內(nèi)的表中。使用兩種框架的目的都是為了減少與關(guān)系數(shù)據(jù)庫有關(guān)的開發(fā)時間。但是,圖 4 演示了兩者在設(shè)計和配置上的一些根本區(qū)別。
圖 4. Active Record 和 Hibernate 持久性框架的比較
Hibernate
Hibernate 基于 Data Mapper 模式,在這種模式中,特定的映射器類 Session
負責在數(shù)據(jù)庫中持久存儲和檢索數(shù)據(jù)。Hibernate 可以持久存儲任何 Java 對象,只要這個對象符合 JavaBean 規(guī)范。XML 映射文件描述了如何將類映射到數(shù)據(jù)庫中具體的表,并描述了類與其他類的關(guān)系。
清單 3 顯示了 Hibernate 映射文件的一個實例。class
標簽把 Order
對象映射到 ORDERS
表,還有許多子標簽用于描述其屬性、ID 訂單名稱,以及同 models.Item
的一對多關(guān)系。清單 4 顯示了 Order
類本身。
|
|
反射和元編程 以下代碼將實現(xiàn)反射:
這個代碼將實現(xiàn)元編程:
|
Rails 的 ORM 框架叫作 Active Record,它基于同名的設(shè)計模式。Martin Fowler 將 Active Record 描述為“包裝數(shù)據(jù)庫表或視圖中數(shù)據(jù)行的對象,封裝數(shù)據(jù)庫訪問,在數(shù)據(jù)上添加域邏輯”。在 Rails 中,每個域?qū)ο蠖紝U展提供 CRUD 操作的 ActiveRecord::Base
。
與 Hibernate 一樣,Active Record 不需要映射文件;實際上,使用 Active Record 的開發(fā)人員不需要對 getter 或 setter、甚至類的屬性進行編碼。通過一些漂亮的詞匯分析,Active Record 能夠判斷出,Order
類將映射到數(shù)據(jù)庫中的 ORDERS
表。使用 Ruby 反射和元編程的組合,表的列可以變成對象的屬性。訪問器和調(diào)整器也添加了進來。
清單 5 顯示了 Order
類的完成后的代碼。在 Order
類體中有一行代碼定義了它與 Item
對象的關(guān)系。has_many
是一個靜態(tài)方法調(diào)用,符號 :items
是它的參數(shù)。ActiveRecord 用 :items
發(fā)現(xiàn) Item
域?qū)ο螅缓髮⑦@個 Item
對象映射回數(shù)據(jù)庫中的 ITEMS
表。
|
像 清單 5 那樣編碼的 Order
類在運行時提供了一些類和實例方法。表 2 提供了可在 Order
上使用的操作和屬性的部分列表:
類方法 | 實例方法 | 屬性 |
|
|
|
結(jié)束語
雖然 Ruby on Rails 是一個非常新、令人興奮的框架,并且在 Web 社區(qū)中已經(jīng)引起了人們相當?shù)呐d趣,但是它的核心架構(gòu)仍然遵循在 J2EE 中發(fā)現(xiàn)的基本模式。開發(fā)把兩個框架分開的 Web 應(yīng)用程序是一種合理的方法。Rails 更喜歡清楚的代碼而不是配置文件,而 Ruby 語言的動態(tài)性質(zhì)在運行時生成了大部分管道 代碼。大多數(shù) Rails 框架都是作為獨立項目創(chuàng)建的,而且應(yīng)用程序開發(fā)能夠從一組同類組件受益。相比之下,典型的 J2EE 堆棧傾向于構(gòu)建在通常獨立開發(fā)的最好的組件之上,常常用 XML 進行配置并將組件組合在一起。
那么,是否應(yīng)該考慮對下一個 Web 應(yīng)用程序使用 Rails 呢?嗯,為什么不呢?它是編寫得很好的組件堆棧,它們彼此之間工作得很好,并且基于行業(yè)接受的企業(yè)模式。Ruby 語言支持快速開發(fā),并通過生產(chǎn)大多數(shù)應(yīng)用程序管道來添加到框架。熟悉 Java 世界中的 MVC 和 ORM 框架的人們在用 Rails 表達自己的思想時沒有任何困難。
與 J2EE 一起分發(fā)會不會有利于 Rails?絕對不要。J2EE 是一個已經(jīng)設(shè)置好的標準,有許多固定的實現(xiàn),而且,最重要的是,它是一個經(jīng)過驗證的技術(shù)。我建議您下載一份 Rails 的副本,并開始自己鉆研它。許多可用的教程都是介紹性的,這些教程可以讓您立即開始使用 Rails。再次聲明,我并不能保證您會通過使用 Rails 得到快樂,但是我敢打賭您會感到滿意。
- 您可以參閱本文在 developerWorks 全球站點上的 英文原文。
- 請參閱 Ruby on Rails Web site。
- 從 ruby-lang.org 得到關(guān)于 Ruby 的您需要了解的最新信息。
- 發(fā)現(xiàn)更多關(guān)于 Struts 和 Jakarta project 的信息。
- 學習更多關(guān)于 Hibernate 的知識。
- 從 Curt Hibbs 撰寫的“Rolling with Ruby on Rails”(ONLamp.com,2005 年 1 月)得到一份關(guān)于創(chuàng)建 Rails 應(yīng)用程序的好的介紹。
- 在 Sun 的 Blueprints 目錄中尋找 Model-View-Controller 和 Front Controller 模式的簡要解釋說明。
- 在 Martin Fowler's Web site 上了解對 Active Record 和 Data Mapper 模式精簡后的解釋。
- 掌握 Fast-track your Web apps with Ruby on Rails,這樣就可以用這個基于 Ruby 的框架和它的模型-視圖-控制器設(shè)計模式來迅速構(gòu)建和定制應(yīng)用程序(developerWorks,2005 年 6 月)。
- 從 Programming in the Ruby language(developerWorks, 2001 年 7 月)開始研究 Ruby 和它的變量、引用、數(shù)組、對象和方法。
- 在 Struts,MVC 的一種開放源碼實現(xiàn) 中研究 Struts 如何幫助控制 Web 項目中的變化,并提高您的專長(developerWorks,2001 年 2 月)。
- 在 Object-relation mapping without the container 中,學習結(jié)合使用 Hibernate 和 Spring,為企業(yè)應(yīng)用程序構(gòu)建事務(wù)性的持久存儲層(developerWorks,2004 年 4 月)。
- 請參 Wikipedia 的關(guān)于 reflection 和 metaprogramming 定義。
- 請參閱 developerWorks Web Architecture 專區(qū),獲得介紹各種基于 Web 的解決方案的文章。
- 通過參與 developerWorks blogs 加入 developerWorks 社區(qū)。
關(guān)于作者![]() |
posted on 2006-02-08 10:05 天生我才 閱讀(157) 評論(0) 編輯 收藏 所屬分類: Ruby